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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy