Skip to content

Commit 62f80ff

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY() transformation
1 parent a4800a8 commit 62f80ff

File tree

9 files changed

+332
-12
lines changed

9 files changed

+332
-12
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,22 @@ _copyJsonOutput(const JsonOutput *from)
23582358
return newnode;
23592359
}
23602360

2361+
/*
2362+
* _copyJsonArrayCtor
2363+
*/
2364+
static JsonArrayCtor *
2365+
_copyJsonArrayCtor(const JsonArrayCtor *from)
2366+
{
2367+
JsonArrayCtor *newnode = makeNode(JsonArrayCtor);
2368+
2369+
COPY_NODE_FIELD(exprs);
2370+
COPY_NODE_FIELD(output);
2371+
COPY_SCALAR_FIELD(absent_on_null);
2372+
COPY_LOCATION_FIELD(location);
2373+
2374+
return newnode;
2375+
}
2376+
23612377
/* ****************************************************************
23622378
* pathnodes.h copy functions
23632379
*
@@ -5276,6 +5292,9 @@ copyObjectImpl(const void *from)
52765292
case T_JsonOutput:
52775293
retval = _copyJsonOutput(from);
52785294
break;
5295+
case T_JsonArrayCtor:
5296+
retval = _copyJsonArrayCtor(from);
5297+
break;
52795298

52805299
/*
52815300
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,16 @@ raw_expression_tree_walker(Node *node,
40104010
return true;
40114011
}
40124012
break;
4013+
case T_JsonArrayCtor:
4014+
{
4015+
JsonArrayCtor *jac = (JsonArrayCtor *) node;
4016+
4017+
if (walker(jac->output, context))
4018+
return true;
4019+
if (walker(jac->exprs, context))
4020+
return true;
4021+
}
4022+
break;
40134023
default:
40144024
elog(ERROR, "unrecognized node type: %d",
40154025
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static Node *transformIndirection(ParseState *pstate, A_Indirection *ind);
122122
static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
123123
static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
124124
static Node *transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor);
125+
static Node *transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor);
125126
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
126127
List *largs, List *rargs, int location);
127128
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -374,6 +375,10 @@ transformExprRecurse(ParseState *pstate, Node *expr)
374375
result = transformJsonObjectCtor(pstate, (JsonObjectCtor *) expr);
375376
break;
376377

378+
case T_JsonArrayCtor:
379+
result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
380+
break;
381+
377382
default:
378383
/* should not reach here */
379384
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -3995,3 +4000,68 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
39954000

39964001
return coerceJsonFuncExpr(pstate, (Node *) jsctor, jsctor->returning, true);
39974002
}
4003+
4004+
/*
4005+
* Transform JSON_ARRAY() constructor.
4006+
*
4007+
* JSON_ARRAY() is transformed into json[b]_build_array[_ext]() call
4008+
* depending on the output JSON format. The first argument of
4009+
* json[b]_build_array_ext() is absent_on_null.
4010+
*
4011+
* Then function call result is coerced to the target type.
4012+
*/
4013+
static Node *
4014+
transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
4015+
{
4016+
JsonReturning returning;
4017+
JsonCtorExpr *jsctor;
4018+
FuncExpr *fexpr;
4019+
List *args = NIL;
4020+
Oid funcid;
4021+
Oid funcrettype;
4022+
4023+
/* transform element expressions, if any */
4024+
if (ctor->exprs)
4025+
{
4026+
ListCell *lc;
4027+
4028+
/* append the first absent_on_null argument */
4029+
args = lappend(args, makeBoolConst(ctor->absent_on_null, false));
4030+
4031+
/* transform and append element arguments */
4032+
foreach(lc, ctor->exprs)
4033+
{
4034+
JsonValueExpr *jsval = castNode(JsonValueExpr, lfirst(lc));
4035+
Node *val = transformJsonValueExpr(pstate, jsval,
4036+
JS_FORMAT_DEFAULT);
4037+
4038+
args = lappend(args, val);
4039+
}
4040+
}
4041+
4042+
transformJsonOutput(pstate, ctor->output, true, &returning);
4043+
4044+
if (returning.format.type == JS_FORMAT_JSONB)
4045+
{
4046+
funcid = args ? F_JSONB_BUILD_ARRAY_EXT : F_JSONB_BUILD_ARRAY_NOARGS;
4047+
funcrettype = JSONBOID;
4048+
}
4049+
else
4050+
{
4051+
funcid = args ? F_JSON_BUILD_ARRAY_EXT : F_JSON_BUILD_ARRAY_NOARGS;
4052+
funcrettype = JSONOID;
4053+
}
4054+
4055+
fexpr = makeFuncExpr(funcid, funcrettype, args,
4056+
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
4057+
fexpr->location = ctor->location;
4058+
4059+
jsctor = makeNode(JsonCtorExpr);
4060+
jsctor->func = fexpr;
4061+
jsctor->type = JSCTOR_JSON_ARRAY;
4062+
jsctor->returning = returning;
4063+
jsctor->unique = false;
4064+
jsctor->absent_on_null = ctor->absent_on_null;
4065+
4066+
return coerceJsonFuncExpr(pstate, (Node *) jsctor, &returning, true);
4067+
}

src/backend/parser/parse_target.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,9 @@ FigureColnameInternal(Node *node, char **name)
19341934
case T_JsonObjectCtor:
19351935
*name = "json_object";
19361936
return 2;
1937+
case T_JsonArrayCtor:
1938+
*name = "json_array";
1939+
return 2;
19371940
default:
19381941
break;
19391942
}

src/backend/utils/adt/json.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,11 +1237,9 @@ json_build_object_noargs(PG_FUNCTION_ARGS)
12371237
PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
12381238
}
12391239

1240-
/*
1241-
* SQL function json_build_array(variadic "any")
1242-
*/
1243-
Datum
1244-
json_build_array(PG_FUNCTION_ARGS)
1240+
static Datum
1241+
json_build_array_worker(FunctionCallInfo fcinfo, int first_vararg,
1242+
bool absent_on_null)
12451243
{
12461244
int nargs;
12471245
int i;
@@ -1252,7 +1250,8 @@ json_build_array(PG_FUNCTION_ARGS)
12521250
Oid *types;
12531251

12541252
/* fetch argument values to build the array */
1255-
nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
1253+
nargs = extract_variadic_args(fcinfo, first_vararg, false,
1254+
&args, &types, &nulls);
12561255

12571256
if (nargs < 0)
12581257
PG_RETURN_NULL();
@@ -1263,6 +1262,9 @@ json_build_array(PG_FUNCTION_ARGS)
12631262

12641263
for (i = 0; i < nargs; i++)
12651264
{
1265+
if (absent_on_null && nulls[i])
1266+
continue;
1267+
12661268
appendStringInfoString(result, sep);
12671269
sep = ", ";
12681270
add_json(args[i], nulls[i], result, types[i], false);
@@ -1273,6 +1275,24 @@ json_build_array(PG_FUNCTION_ARGS)
12731275
PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
12741276
}
12751277

1278+
/*
1279+
* SQL function json_build_array(variadic "any")
1280+
*/
1281+
Datum
1282+
json_build_array(PG_FUNCTION_ARGS)
1283+
{
1284+
return json_build_array_worker(fcinfo, 0, false);
1285+
}
1286+
1287+
/*
1288+
* SQL function json_build_array_ext(absent_on_null bool, variadic "any")
1289+
*/
1290+
Datum
1291+
json_build_array_ext(PG_FUNCTION_ARGS)
1292+
{
1293+
return json_build_array_worker(fcinfo, 1, PG_GETARG_BOOL(0));
1294+
}
1295+
12761296
/*
12771297
* degenerate case of json_build_array where it gets 0 arguments.
12781298
*/

src/backend/utils/adt/jsonb.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,11 +1237,9 @@ jsonb_build_object_noargs(PG_FUNCTION_ARGS)
12371237
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
12381238
}
12391239

1240-
/*
1241-
* SQL function jsonb_build_array(variadic "any")
1242-
*/
1243-
Datum
1244-
jsonb_build_array(PG_FUNCTION_ARGS)
1240+
static Datum
1241+
jsonb_build_array_worker(FunctionCallInfo fcinfo, int first_vararg,
1242+
bool absent_on_null)
12451243
{
12461244
int nargs;
12471245
int i;
@@ -1251,7 +1249,8 @@ jsonb_build_array(PG_FUNCTION_ARGS)
12511249
Oid *types;
12521250

12531251
/* build argument values to build the array */
1254-
nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1252+
nargs = extract_variadic_args(fcinfo, first_vararg, true,
1253+
&args, &types, &nulls);
12551254

12561255
if (nargs < 0)
12571256
PG_RETURN_NULL();
@@ -1261,13 +1260,36 @@ jsonb_build_array(PG_FUNCTION_ARGS)
12611260
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
12621261

12631262
for (i = 0; i < nargs; i++)
1263+
{
1264+
if (absent_on_null && nulls[i])
1265+
continue;
1266+
12641267
add_jsonb(args[i], nulls[i], &result, types[i], false);
1268+
}
12651269

12661270
result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
12671271

12681272
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
12691273
}
12701274

1275+
/*
1276+
* SQL function jsonb_build_array(variadic "any")
1277+
*/
1278+
Datum
1279+
jsonb_build_array(PG_FUNCTION_ARGS)
1280+
{
1281+
return jsonb_build_array_worker(fcinfo, 0, false);
1282+
}
1283+
1284+
/*
1285+
* SQL function jsonb_build_array_ext(absent_on_null bool, variadic "any")
1286+
*/
1287+
Datum
1288+
jsonb_build_array_ext(PG_FUNCTION_ARGS)
1289+
{
1290+
return jsonb_build_array_worker(fcinfo, 1, PG_GETARG_BOOL(0));
1291+
}
1292+
12711293
/*
12721294
* degenerate case of jsonb_build_array where it gets 0 arguments.
12731295
*/

src/include/catalog/pg_proc.dat

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8397,6 +8397,11 @@
83978397
proname => 'json_build_array', proisstrict => 'f', provolatile => 's',
83988398
prorettype => 'json', proargtypes => '',
83998399
prosrc => 'json_build_array_noargs' },
8400+
{ oid => '2228', descr => 'build a json array from any inputs',
8401+
proname => 'json_build_array_ext', provariadic => 'any', proisstrict => 'f',
8402+
provolatile => 's', prorettype => 'json', proargtypes => 'bool any',
8403+
proallargtypes => '{bool,any}', proargmodes => '{i,v}',
8404+
prosrc => 'json_build_array_ext' },
84008405
{ oid => '3200',
84018406
descr => 'build a json object from pairwise key/value inputs',
84028407
proname => 'json_build_object', provariadic => 'any', proisstrict => 'f',
@@ -9272,6 +9277,11 @@
92729277
proname => 'jsonb_build_array', proisstrict => 'f', provolatile => 's',
92739278
prorettype => 'jsonb', proargtypes => '',
92749279
prosrc => 'jsonb_build_array_noargs' },
9280+
{ oid => '6068', descr => 'build a jsonb array from any inputs',
9281+
proname => 'jsonb_build_array_ext', provariadic => 'any', proisstrict => 'f',
9282+
provolatile => 's', prorettype => 'jsonb', proargtypes => 'bool any',
9283+
proallargtypes => '{bool,any}', proargmodes => '{i,v}',
9284+
prosrc => 'jsonb_build_array_ext' },
92759285
{ oid => '3273',
92769286
descr => 'build a jsonb object from pairwise key/value inputs',
92779287
proname => 'jsonb_build_object', provariadic => 'any', proisstrict => 'f',

0 commit comments

Comments
 (0)