Skip to content

Commit ff13af0

Browse files
author
Commitfest Bot
committed
[CF 5930] v2 - Making jsonb_agg() faster
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5930 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/[email protected] Author(s): Tom Lane
2 parents d3111cb + 6b981d4 commit ff13af0

File tree

8 files changed

+629
-702
lines changed

8 files changed

+629
-702
lines changed

contrib/hstore/hstore_io.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,10 +1439,9 @@ hstore_to_jsonb(PG_FUNCTION_ARGS)
14391439
int count = HS_COUNT(in);
14401440
char *base = STRPTR(in);
14411441
HEntry *entries = ARRPTR(in);
1442-
JsonbParseState *state = NULL;
1443-
JsonbValue *res;
1442+
JsonbInState state = {0};
14441443

1445-
(void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
1444+
pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
14461445

14471446
for (i = 0; i < count; i++)
14481447
{
@@ -1453,7 +1452,7 @@ hstore_to_jsonb(PG_FUNCTION_ARGS)
14531452
key.val.string.len = HSTORE_KEYLEN(entries, i);
14541453
key.val.string.val = HSTORE_KEY(entries, base, i);
14551454

1456-
(void) pushJsonbValue(&state, WJB_KEY, &key);
1455+
pushJsonbValue(&state, WJB_KEY, &key);
14571456

14581457
if (HSTORE_VALISNULL(entries, i))
14591458
{
@@ -1465,12 +1464,12 @@ hstore_to_jsonb(PG_FUNCTION_ARGS)
14651464
val.val.string.len = HSTORE_VALLEN(entries, i);
14661465
val.val.string.val = HSTORE_VAL(entries, base, i);
14671466
}
1468-
(void) pushJsonbValue(&state, WJB_VALUE, &val);
1467+
pushJsonbValue(&state, WJB_VALUE, &val);
14691468
}
14701469

1471-
res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
1470+
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
14721471

1473-
PG_RETURN_POINTER(JsonbValueToJsonb(res));
1472+
PG_RETURN_POINTER(JsonbValueToJsonb(state.result));
14741473
}
14751474

14761475
PG_FUNCTION_INFO_V1(hstore_to_jsonb_loose);
@@ -1482,13 +1481,12 @@ hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
14821481
int count = HS_COUNT(in);
14831482
char *base = STRPTR(in);
14841483
HEntry *entries = ARRPTR(in);
1485-
JsonbParseState *state = NULL;
1486-
JsonbValue *res;
1484+
JsonbInState state = {0};
14871485
StringInfoData tmp;
14881486

14891487
initStringInfo(&tmp);
14901488

1491-
(void) pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
1489+
pushJsonbValue(&state, WJB_BEGIN_OBJECT, NULL);
14921490

14931491
for (i = 0; i < count; i++)
14941492
{
@@ -1499,7 +1497,7 @@ hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
14991497
key.val.string.len = HSTORE_KEYLEN(entries, i);
15001498
key.val.string.val = HSTORE_KEY(entries, base, i);
15011499

1502-
(void) pushJsonbValue(&state, WJB_KEY, &key);
1500+
pushJsonbValue(&state, WJB_KEY, &key);
15031501

15041502
if (HSTORE_VALISNULL(entries, i))
15051503
{
@@ -1541,10 +1539,10 @@ hstore_to_jsonb_loose(PG_FUNCTION_ARGS)
15411539
val.val.string.val = HSTORE_VAL(entries, base, i);
15421540
}
15431541
}
1544-
(void) pushJsonbValue(&state, WJB_VALUE, &val);
1542+
pushJsonbValue(&state, WJB_VALUE, &val);
15451543
}
15461544

1547-
res = pushJsonbValue(&state, WJB_END_OBJECT, NULL);
1545+
pushJsonbValue(&state, WJB_END_OBJECT, NULL);
15481546

1549-
PG_RETURN_POINTER(JsonbValueToJsonb(res));
1547+
PG_RETURN_POINTER(JsonbValueToJsonb(state.result));
15501548
}

contrib/jsonb_plperl/jsonb_plperl.c

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ PG_MODULE_MAGIC_EXT(
1313
);
1414

1515
static SV *Jsonb_to_SV(JsonbContainer *jsonb);
16-
static JsonbValue *SV_to_JsonbValue(SV *obj, JsonbParseState **ps, bool is_elem);
16+
static void SV_to_JsonbValue(SV *obj, JsonbInState *ps, bool is_elem);
1717

1818

1919
static SV *
@@ -127,8 +127,8 @@ Jsonb_to_SV(JsonbContainer *jsonb)
127127
}
128128
}
129129

130-
static JsonbValue *
131-
AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
130+
static void
131+
AV_to_JsonbValue(AV *in, JsonbInState *jsonb_state)
132132
{
133133
dTHX;
134134
SSize_t pcount = av_len(in) + 1;
@@ -141,14 +141,14 @@ AV_to_JsonbValue(AV *in, JsonbParseState **jsonb_state)
141141
SV **value = av_fetch(in, i, FALSE);
142142

143143
if (value)
144-
(void) SV_to_JsonbValue(*value, jsonb_state, true);
144+
SV_to_JsonbValue(*value, jsonb_state, true);
145145
}
146146

147-
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
147+
pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
148148
}
149149

150-
static JsonbValue *
151-
HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
150+
static void
151+
HV_to_JsonbValue(HV *obj, JsonbInState *jsonb_state)
152152
{
153153
dTHX;
154154
JsonbValue key;
@@ -167,14 +167,14 @@ HV_to_JsonbValue(HV *obj, JsonbParseState **jsonb_state)
167167
key.val.string.val = pnstrdup(kstr, klen);
168168
key.val.string.len = klen;
169169
pushJsonbValue(jsonb_state, WJB_KEY, &key);
170-
(void) SV_to_JsonbValue(val, jsonb_state, false);
170+
SV_to_JsonbValue(val, jsonb_state, false);
171171
}
172172

173-
return pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
173+
pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
174174
}
175175

176-
static JsonbValue *
177-
SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
176+
static void
177+
SV_to_JsonbValue(SV *in, JsonbInState *jsonb_state, bool is_elem)
178178
{
179179
dTHX;
180180
JsonbValue out; /* result */
@@ -186,10 +186,12 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
186186
switch (SvTYPE(in))
187187
{
188188
case SVt_PVAV:
189-
return AV_to_JsonbValue((AV *) in, jsonb_state);
189+
AV_to_JsonbValue((AV *) in, jsonb_state);
190+
return;
190191

191192
case SVt_PVHV:
192-
return HV_to_JsonbValue((HV *) in, jsonb_state);
193+
HV_to_JsonbValue((HV *) in, jsonb_state);
194+
return;
193195

194196
default:
195197
if (!SvOK(in))
@@ -259,14 +261,18 @@ SV_to_JsonbValue(SV *in, JsonbParseState **jsonb_state, bool is_elem)
259261
ereport(ERROR,
260262
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
261263
errmsg("cannot transform this Perl type to jsonb")));
262-
return NULL;
263264
}
264265
}
265266

266267
/* Push result into 'jsonb_state' unless it is a raw scalar. */
267-
return *jsonb_state
268-
? pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out)
269-
: memcpy(palloc(sizeof(JsonbValue)), &out, sizeof(JsonbValue));
268+
if (jsonb_state->parseState)
269+
pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, &out);
270+
else
271+
{
272+
/* XXX Ugly hack */
273+
jsonb_state->result = palloc(sizeof(JsonbValue));
274+
memcpy(jsonb_state->result, &out, sizeof(JsonbValue));
275+
}
270276
}
271277

272278

@@ -289,10 +295,9 @@ Datum
289295
plperl_to_jsonb(PG_FUNCTION_ARGS)
290296
{
291297
dTHX;
292-
JsonbParseState *jsonb_state = NULL;
293298
SV *in = (SV *) PG_GETARG_POINTER(0);
294-
JsonbValue *out = SV_to_JsonbValue(in, &jsonb_state, true);
295-
Jsonb *result = JsonbValueToJsonb(out);
299+
JsonbInState jsonb_state = {0};
296300

297-
PG_RETURN_JSONB_P(result);
301+
SV_to_JsonbValue(in, &jsonb_state, true);
302+
PG_RETURN_JSONB_P(JsonbValueToJsonb(jsonb_state.result));
298303
}

contrib/jsonb_plpython/jsonb_plpython.c

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ static PLy_elog_impl_t PLy_elog_impl_p;
2626
static PyObject *decimal_constructor;
2727

2828
static PyObject *PLyObject_FromJsonbContainer(JsonbContainer *jsonb);
29-
static JsonbValue *PLyObject_ToJsonbValue(PyObject *obj,
30-
JsonbParseState **jsonb_state, bool is_elem);
29+
static void PLyObject_ToJsonbValue(PyObject *obj,
30+
JsonbInState *jsonb_state, bool is_elem);
3131

3232
typedef PyObject *(*PLyUnicode_FromStringAndSize_t)
3333
(const char *s, Py_ssize_t size);
@@ -261,12 +261,11 @@ PLyObject_FromJsonbContainer(JsonbContainer *jsonb)
261261
*
262262
* Transform Python dict to JsonbValue.
263263
*/
264-
static JsonbValue *
265-
PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
264+
static void
265+
PLyMapping_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state)
266266
{
267267
Py_ssize_t pcount;
268268
PyObject *volatile items;
269-
JsonbValue *volatile out;
270269

271270
pcount = PyMapping_Size(obj);
272271
items = PyMapping_Items(obj);
@@ -297,19 +296,17 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
297296
PLyUnicode_ToJsonbValue(key, &jbvKey);
298297
}
299298

300-
(void) pushJsonbValue(jsonb_state, WJB_KEY, &jbvKey);
301-
(void) PLyObject_ToJsonbValue(value, jsonb_state, false);
299+
pushJsonbValue(jsonb_state, WJB_KEY, &jbvKey);
300+
PLyObject_ToJsonbValue(value, jsonb_state, false);
302301
}
303302

304-
out = pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
303+
pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
305304
}
306305
PG_FINALLY();
307306
{
308307
Py_DECREF(items);
309308
}
310309
PG_END_TRY();
311-
312-
return out;
313310
}
314311

315312
/*
@@ -318,8 +315,8 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
318315
* Transform python list to JsonbValue. Expects transformed PyObject and
319316
* a state required for jsonb construction.
320317
*/
321-
static JsonbValue *
322-
PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
318+
static void
319+
PLySequence_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state)
323320
{
324321
Py_ssize_t i;
325322
Py_ssize_t pcount;
@@ -336,7 +333,7 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
336333
value = PySequence_GetItem(obj, i);
337334
Assert(value);
338335

339-
(void) PLyObject_ToJsonbValue(value, jsonb_state, true);
336+
PLyObject_ToJsonbValue(value, jsonb_state, true);
340337
Py_XDECREF(value);
341338
value = NULL;
342339
}
@@ -348,7 +345,7 @@ PLySequence_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
348345
}
349346
PG_END_TRY();
350347

351-
return pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
348+
pushJsonbValue(jsonb_state, WJB_END_ARRAY, NULL);
352349
}
353350

354351
/*
@@ -406,17 +403,23 @@ PLyNumber_ToJsonbValue(PyObject *obj, JsonbValue *jbvNum)
406403
*
407404
* Transform python object to JsonbValue.
408405
*/
409-
static JsonbValue *
410-
PLyObject_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state, bool is_elem)
406+
static void
407+
PLyObject_ToJsonbValue(PyObject *obj, JsonbInState *jsonb_state, bool is_elem)
411408
{
412409
JsonbValue *out;
413410

414411
if (!PyUnicode_Check(obj))
415412
{
416413
if (PySequence_Check(obj))
417-
return PLySequence_ToJsonbValue(obj, jsonb_state);
414+
{
415+
PLySequence_ToJsonbValue(obj, jsonb_state);
416+
return;
417+
}
418418
else if (PyMapping_Check(obj))
419-
return PLyMapping_ToJsonbValue(obj, jsonb_state);
419+
{
420+
PLyMapping_ToJsonbValue(obj, jsonb_state);
421+
return;
422+
}
420423
}
421424

422425
out = palloc(sizeof(JsonbValue));
@@ -443,10 +446,14 @@ PLyObject_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state, bool is_ele
443446
errmsg("Python type \"%s\" cannot be transformed to jsonb",
444447
PLyObject_AsString((PyObject *) obj->ob_type))));
445448

446-
/* Push result into 'jsonb_state' unless it is raw scalar value. */
447-
return (*jsonb_state ?
448-
pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, out) :
449-
out);
449+
/* Push result into 'jsonb_state' unless it is a raw scalar. */
450+
if (jsonb_state->parseState)
451+
pushJsonbValue(jsonb_state, is_elem ? WJB_ELEM : WJB_VALUE, out);
452+
else
453+
{
454+
/* XXX Ugly hack */
455+
jsonb_state->result = out;
456+
}
450457
}
451458

452459
/*
@@ -458,13 +465,11 @@ PG_FUNCTION_INFO_V1(plpython_to_jsonb);
458465
Datum
459466
plpython_to_jsonb(PG_FUNCTION_ARGS)
460467
{
461-
PyObject *obj;
462-
JsonbValue *out;
463-
JsonbParseState *jsonb_state = NULL;
468+
PyObject *obj = (PyObject *) PG_GETARG_POINTER(0);
469+
JsonbInState jsonb_state = {0};
464470

465-
obj = (PyObject *) PG_GETARG_POINTER(0);
466-
out = PLyObject_ToJsonbValue(obj, &jsonb_state, true);
467-
PG_RETURN_POINTER(JsonbValueToJsonb(out));
471+
PLyObject_ToJsonbValue(obj, &jsonb_state, true);
472+
PG_RETURN_POINTER(JsonbValueToJsonb(jsonb_state.result));
468473
}
469474

470475
/*

0 commit comments

Comments
 (0)