Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d602634

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY() transformation
1 parent 18b74ac commit d602634

File tree

9 files changed

+327
-12
lines changed

9 files changed

+327
-12
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,22 @@ _copyJsonObjectCtor(const JsonObjectCtor *from)
21532153
return newnode;
21542154
}
21552155

2156+
/*
2157+
* _copyJsonArrayCtor
2158+
*/
2159+
static JsonArrayCtor *
2160+
_copyJsonArrayCtor(const JsonArrayCtor *from)
2161+
{
2162+
JsonArrayCtor *newnode = makeNode(JsonArrayCtor);
2163+
2164+
COPY_NODE_FIELD(exprs);
2165+
COPY_NODE_FIELD(output);
2166+
COPY_SCALAR_FIELD(absent_on_null);
2167+
COPY_LOCATION_FIELD(location);
2168+
2169+
return newnode;
2170+
}
2171+
21562172
/* ****************************************************************
21572173
* relation.h copy functions
21582174
*
@@ -5026,6 +5042,9 @@ copyObjectImpl(const void *from)
50265042
case T_JsonObjectCtor:
50275043
retval = _copyJsonObjectCtor(from);
50285044
break;
5045+
case T_JsonArrayCtor:
5046+
retval = _copyJsonArrayCtor(from);
5047+
break;
50295048

50305049
/*
50315050
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3703,6 +3703,16 @@ raw_expression_tree_walker(Node *node,
37033703
return true;
37043704
}
37053705
break;
3706+
case T_JsonArrayCtor:
3707+
{
3708+
JsonArrayCtor *jac = (JsonArrayCtor *) node;
3709+
3710+
if (walker(jac->output, context))
3711+
return true;
3712+
if (walker(jac->exprs, context))
3713+
return true;
3714+
}
3715+
break;
37063716
default:
37073717
elog(ERROR, "unrecognized node type: %d",
37083718
(int) nodeTag(node));

src/backend/parser/parse_expr.c

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

379+
case T_JsonArrayCtor:
380+
result = transformJsonArrayCtor(pstate, (JsonArrayCtor *) expr);
381+
break;
382+
378383
default:
379384
/* should not reach here */
380385
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -3833,3 +3838,60 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38333838
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &ctor->output->returning,
38343839
true);
38353840
}
3841+
3842+
/*
3843+
* Transform JSON_ARRAY() constructor.
3844+
*
3845+
* JSON_ARRAY() is transformed into json[b]_build_array[_ext]() call
3846+
* depending on the output JSON format. The first argument of
3847+
* json[b]_build_array_ext() is absent_on_null.
3848+
*
3849+
* Then function call result is coerced to the target type.
3850+
*/
3851+
static Node *
3852+
transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
3853+
{
3854+
FuncExpr *fexpr;
3855+
List *args = NIL;
3856+
Oid funcid;
3857+
Oid funcrettype;
3858+
3859+
/* transform element expressions, if any */
3860+
if (ctor->exprs)
3861+
{
3862+
ListCell *lc;
3863+
3864+
/* append the first absent_on_null argument */
3865+
args = lappend(args, makeBoolConst(ctor->absent_on_null, false));
3866+
3867+
/* transform and append element arguments */
3868+
foreach(lc, ctor->exprs)
3869+
{
3870+
JsonValueExpr *jsval = castNode(JsonValueExpr, lfirst(lc));
3871+
Node *val = transformJsonValueExpr(pstate, jsval,
3872+
JS_FORMAT_DEFAULT);
3873+
3874+
args = lappend(args, val);
3875+
}
3876+
}
3877+
3878+
transformJsonOutput(pstate, &ctor->output, true);
3879+
3880+
if (ctor->output->returning.format.type == JS_FORMAT_JSONB)
3881+
{
3882+
funcid = args ? F_JSONB_BUILD_ARRAY_EXT : F_JSONB_BUILD_ARRAY_NOARGS;
3883+
funcrettype = JSONBOID;
3884+
}
3885+
else
3886+
{
3887+
funcid = args ? F_JSON_BUILD_ARRAY_EXT : F_JSON_BUILD_ARRAY_NOARGS;
3888+
funcrettype = JSONOID;
3889+
}
3890+
3891+
fexpr = makeFuncExpr(funcid, funcrettype, args,
3892+
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
3893+
fexpr->location = ctor->location;
3894+
3895+
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &ctor->output->returning,
3896+
true);
3897+
}

src/backend/utils/adt/json.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2340,11 +2340,9 @@ json_build_object_noargs(PG_FUNCTION_ARGS)
23402340
PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
23412341
}
23422342

2343-
/*
2344-
* SQL function json_build_array(variadic "any")
2345-
*/
2346-
Datum
2347-
json_build_array(PG_FUNCTION_ARGS)
2343+
static Datum
2344+
json_build_array_worker(FunctionCallInfo fcinfo, int first_vararg,
2345+
bool absent_on_null)
23482346
{
23492347
int nargs;
23502348
int i;
@@ -2355,7 +2353,8 @@ json_build_array(PG_FUNCTION_ARGS)
23552353
Oid *types;
23562354

23572355
/* fetch argument values to build the array */
2358-
nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
2356+
nargs = extract_variadic_args(fcinfo, first_vararg, false,
2357+
&args, &types, &nulls);
23592358

23602359
if (nargs < 0)
23612360
PG_RETURN_NULL();
@@ -2366,6 +2365,9 @@ json_build_array(PG_FUNCTION_ARGS)
23662365

23672366
for (i = 0; i < nargs; i++)
23682367
{
2368+
if (absent_on_null && nulls[i])
2369+
continue;
2370+
23692371
appendStringInfoString(result, sep);
23702372
sep = ", ";
23712373
add_json(args[i], nulls[i], result, types[i], false);
@@ -2376,6 +2378,24 @@ json_build_array(PG_FUNCTION_ARGS)
23762378
PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
23772379
}
23782380

2381+
/*
2382+
* SQL function json_build_array(variadic "any")
2383+
*/
2384+
Datum
2385+
json_build_array(PG_FUNCTION_ARGS)
2386+
{
2387+
return json_build_array_worker(fcinfo, 0, false);
2388+
}
2389+
2390+
/*
2391+
* SQL function json_build_array_ext(absent_on_null bool, variadic "any")
2392+
*/
2393+
Datum
2394+
json_build_array_ext(PG_FUNCTION_ARGS)
2395+
{
2396+
return json_build_array_worker(fcinfo, 1, PG_GETARG_BOOL(0));
2397+
}
2398+
23792399
/*
23802400
* degenerate case of json_build_array where it gets 0 arguments.
23812401
*/

src/backend/utils/adt/jsonb.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,11 +1395,9 @@ jsonb_build_object_noargs(PG_FUNCTION_ARGS)
13951395
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
13961396
}
13971397

1398-
/*
1399-
* SQL function jsonb_build_array(variadic "any")
1400-
*/
1401-
Datum
1402-
jsonb_build_array(PG_FUNCTION_ARGS)
1398+
static Datum
1399+
jsonb_build_array_worker(FunctionCallInfo fcinfo, int first_vararg,
1400+
bool absent_on_null)
14031401
{
14041402
int nargs;
14051403
int i;
@@ -1409,7 +1407,8 @@ jsonb_build_array(PG_FUNCTION_ARGS)
14091407
Oid *types;
14101408

14111409
/* build argument values to build the array */
1412-
nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1410+
nargs = extract_variadic_args(fcinfo, first_vararg, true,
1411+
&args, &types, &nulls);
14131412

14141413
if (nargs < 0)
14151414
PG_RETURN_NULL();
@@ -1419,13 +1418,36 @@ jsonb_build_array(PG_FUNCTION_ARGS)
14191418
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
14201419

14211420
for (i = 0; i < nargs; i++)
1421+
{
1422+
if (absent_on_null && nulls[i])
1423+
continue;
1424+
14221425
add_jsonb(args[i], nulls[i], &result, types[i], false);
1426+
}
14231427

14241428
result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
14251429

14261430
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
14271431
}
14281432

1433+
/*
1434+
* SQL function jsonb_build_array(variadic "any")
1435+
*/
1436+
Datum
1437+
jsonb_build_array(PG_FUNCTION_ARGS)
1438+
{
1439+
return jsonb_build_array_worker(fcinfo, 0, false);
1440+
}
1441+
1442+
/*
1443+
* SQL function jsonb_build_array_ext(absent_on_null bool, variadic "any")
1444+
*/
1445+
Datum
1446+
jsonb_build_array_ext(PG_FUNCTION_ARGS)
1447+
{
1448+
return jsonb_build_array_worker(fcinfo, 1, PG_GETARG_BOOL(0));
1449+
}
1450+
14291451
/*
14301452
* degenerate case of jsonb_build_array where it gets 0 arguments.
14311453
*/

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4523,6 +4523,8 @@ DATA(insert OID = 3198 ( json_build_array PGNSP PGUID 12 1 0 2276 0 f f f f
45234523
DESCR("build a json array from any inputs");
45244524
DATA(insert OID = 3199 ( json_build_array PGNSP PGUID 12 1 0 0 0 f f f f f f s s 0 0 114 "" _null_ _null_ _null_ _null_ _null_ json_build_array_noargs _null_ _null_ _null_ ));
45254525
DESCR("build an empty json array");
4526+
DATA(insert OID = 3998 ( json_build_array_ext PGNSP PGUID 12 1 0 2276 0 f f f f f f s s 2 0 114 "16 2276" "{16,2276}" "{i,v}" _null_ _null_ _null_ json_build_array_ext _null_ _null_ _null_ ));
4527+
DESCR("build a json array from any inputs");
45264528
DATA(insert OID = 3200 ( json_build_object PGNSP PGUID 12 1 0 2276 0 f f f f f f s s 1 0 114 "2276" "{2276}" "{v}" _null_ _null_ _null_ json_build_object _null_ _null_ _null_ ));
45274529
DESCR("build a json object from pairwise key/value inputs");
45284530
DATA(insert OID = 3201 ( json_build_object PGNSP PGUID 12 1 0 0 0 f f f f f f s s 0 0 114 "" _null_ _null_ _null_ _null_ _null_ json_build_object_noargs _null_ _null_ _null_ ));
@@ -4985,6 +4987,8 @@ DATA(insert OID = 3271 ( jsonb_build_array PGNSP PGUID 12 1 0 2276 0 f f f f
49854987
DESCR("build a jsonb array from any inputs");
49864988
DATA(insert OID = 3272 ( jsonb_build_array PGNSP PGUID 12 1 0 0 0 f f f f f f s s 0 0 3802 "" _null_ _null_ _null_ _null_ _null_ jsonb_build_array_noargs _null_ _null_ _null_ ));
49874989
DESCR("build an empty jsonb array");
4990+
DATA(insert OID = 6068 ( jsonb_build_array_ext PGNSP PGUID 12 1 0 2276 0 f f f f f f s s 2 0 3802 "16 2276" "{16,2276}" "{i,v}" _null_ _null_ _null_ jsonb_build_array_ext _null_ _null_ _null_ ));
4991+
DESCR("build a jsonb array from any inputs");
49884992
DATA(insert OID = 3273 ( jsonb_build_object PGNSP PGUID 12 1 0 2276 0 f f f f f f s s 1 0 3802 "2276" "{2276}" "{v}" _null_ _null_ _null_ jsonb_build_object _null_ _null_ _null_ ));
49894993
DESCR("build a jsonb object from pairwise key/value inputs");
49904994
DATA(insert OID = 3274 ( jsonb_build_object PGNSP PGUID 12 1 0 0 0 f f f f f f s s 0 0 3802 "" _null_ _null_ _null_ _null_ _null_ jsonb_build_object_noargs _null_ _null_ _null_ ));

0 commit comments

Comments
 (0)