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

Commit b47bb7b

Browse files
author
Nikita Glukhov
committed
Add JSON_ARRAY() transformation
1 parent 3f3222a commit b47bb7b

File tree

9 files changed

+325
-12
lines changed

9 files changed

+325
-12
lines changed

src/backend/nodes/copyfuncs.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,22 @@ _copyJsonCtorOpts(const JsonCtorOpts *from)
21932193
return newnode;
21942194
}
21952195

2196+
/*
2197+
* _copyJsonArrayCtor
2198+
*/
2199+
static JsonArrayCtor *
2200+
_copyJsonArrayCtor(const JsonArrayCtor *from)
2201+
{
2202+
JsonArrayCtor *newnode = makeNode(JsonArrayCtor);
2203+
2204+
COPY_NODE_FIELD(exprs);
2205+
COPY_NODE_FIELD(output);
2206+
COPY_SCALAR_FIELD(absent_on_null);
2207+
COPY_LOCATION_FIELD(location);
2208+
2209+
return newnode;
2210+
}
2211+
21962212
/* ****************************************************************
21972213
* relation.h copy functions
21982214
*
@@ -5057,6 +5073,9 @@ copyObjectImpl(const void *from)
50575073
case T_JsonObjectCtor:
50585074
retval = _copyJsonObjectCtor(from);
50595075
break;
5076+
case T_JsonArrayCtor:
5077+
retval = _copyJsonArrayCtor(from);
5078+
break;
50605079

50615080
/*
50625081
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3730,6 +3730,16 @@ raw_expression_tree_walker(Node *node,
37303730
return true;
37313731
}
37323732
break;
3733+
case T_JsonArrayCtor:
3734+
{
3735+
JsonArrayCtor *jac = (JsonArrayCtor *) node;
3736+
3737+
if (walker(jac->output, context))
3738+
return true;
3739+
if (walker(jac->exprs, context))
3740+
return true;
3741+
}
3742+
break;
37333743
default:
37343744
elog(ERROR, "unrecognized node type: %d",
37353745
(int) nodeTag(node));

src/backend/parser/parse_expr.c

Lines changed: 65 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));
@@ -3851,3 +3856,63 @@ transformJsonObjectCtor(ParseState *pstate, JsonObjectCtor *ctor)
38513856

38523857
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
38533858
}
3859+
3860+
/*
3861+
* Transform JSON_ARRAY() constructor.
3862+
*
3863+
* JSON_ARRAY() is transformed into json[b]_build_array[_ext]() call
3864+
* depending on the output JSON format. The first argument of
3865+
* json[b]_build_array_ext() is absent_on_null.
3866+
*
3867+
* Then function call result is coerced to the target type.
3868+
*/
3869+
static Node *
3870+
transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
3871+
{
3872+
JsonReturning returning;
3873+
FuncExpr *fexpr;
3874+
List *args = NIL;
3875+
Oid funcid;
3876+
Oid funcrettype;
3877+
3878+
/* transform element expressions, if any */
3879+
if (ctor->exprs)
3880+
{
3881+
ListCell *lc;
3882+
3883+
/* append the first absent_on_null argument */
3884+
args = lappend(args, makeBoolConst(ctor->absent_on_null, false));
3885+
3886+
/* transform and append element arguments */
3887+
foreach(lc, ctor->exprs)
3888+
{
3889+
JsonValueExpr *jsval = castNode(JsonValueExpr, lfirst(lc));
3890+
Node *val = transformJsonValueExpr(pstate, jsval,
3891+
JS_FORMAT_DEFAULT);
3892+
3893+
args = lappend(args, val);
3894+
}
3895+
}
3896+
3897+
transformJsonOutput(pstate, ctor->output, true, &returning);
3898+
3899+
if (returning.format.type == JS_FORMAT_JSONB)
3900+
{
3901+
funcid = args ? F_JSONB_BUILD_ARRAY_EXT : F_JSONB_BUILD_ARRAY_NOARGS;
3902+
funcrettype = JSONBOID;
3903+
}
3904+
else
3905+
{
3906+
funcid = args ? F_JSON_BUILD_ARRAY_EXT : F_JSON_BUILD_ARRAY_NOARGS;
3907+
funcrettype = JSONOID;
3908+
}
3909+
3910+
fexpr = makeFuncExpr(funcid, funcrettype, args,
3911+
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
3912+
fexpr->location = ctor->location;
3913+
fexpr->funcformat2 = FUNCFMT_JSON_ARRAY;
3914+
fexpr->funcformatopts = (Node *) makeJsonCtorOpts(&returning, false,
3915+
ctor->absent_on_null);
3916+
3917+
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
3918+
}

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/backend/utils/adt/ruleutils.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9035,6 +9035,13 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
90359035
firstarg = 2;
90369036
use_variadic = false;
90379037
break;
9038+
9039+
case FUNCFMT_JSON_ARRAY:
9040+
funcname = "JSON_ARRAY";
9041+
firstarg = 0;
9042+
use_variadic = false;
9043+
break;
9044+
90389045
default:
90399046
funcname = generate_function_name(funcoid, nargs,
90409047
argnames, argtypes,

src/include/catalog/pg_proc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4478,6 +4478,8 @@ DATA(insert OID = 3198 ( json_build_array PGNSP PGUID 12 1 0 2276 0 f f f f
44784478
DESCR("build a json array from any inputs");
44794479
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_ ));
44804480
DESCR("build an empty json array");
4481+
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_ ));
4482+
DESCR("build a json array from any inputs");
44814483
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_ ));
44824484
DESCR("build a json object from pairwise key/value inputs");
44834485
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_ ));
@@ -4936,6 +4938,8 @@ DATA(insert OID = 3271 ( jsonb_build_array PGNSP PGUID 12 1 0 2276 0 f f f f
49364938
DESCR("build a jsonb array from any inputs");
49374939
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_ ));
49384940
DESCR("build an empty jsonb array");
4941+
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_ ));
4942+
DESCR("build a jsonb array from any inputs");
49394943
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_ ));
49404944
DESCR("build a jsonb object from pairwise key/value inputs");
49414945
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)