Skip to content

Commit f4fb45d

Browse files
committed
SQL/JSON constructors
This patch introduces the SQL/JSON standard constructors for JSON: JSON() JSON_ARRAY() JSON_ARRAYAGG() JSON_OBJECT() JSON_OBJECTAGG() For the most part these functions provide facilities that mimic existing json/jsonb functions. However, they also offer some useful additional functionality. In addition to text input, the JSON() function accepts bytea input, which it will decode and constuct a json value from. The other functions provide useful options for handling duplicate keys and null values. This series of patches will be followed by a consolidated documentation patch. Nikita Glukhov Reviewers have included (in no particular order) Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zihong Yu, Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby. Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
1 parent f79b803 commit f4fb45d

37 files changed

+3615
-130
lines changed

src/backend/executor/execExpr.c

+63
Original file line numberDiff line numberDiff line change
@@ -2450,6 +2450,69 @@ ExecInitExprRec(Expr *node, ExprState *state,
24502450
break;
24512451
}
24522452

2453+
case T_JsonConstructorExpr:
2454+
{
2455+
JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
2456+
List *args = ctor->args;
2457+
ListCell *lc;
2458+
int nargs = list_length(args);
2459+
int argno = 0;
2460+
2461+
if (ctor->func)
2462+
{
2463+
ExecInitExprRec(ctor->func, state, resv, resnull);
2464+
}
2465+
else
2466+
{
2467+
scratch.opcode = EEOP_JSON_CONSTRUCTOR;
2468+
scratch.d.json_constructor.constructor = ctor;
2469+
scratch.d.json_constructor.arg_values = palloc(sizeof(Datum) * nargs);
2470+
scratch.d.json_constructor.arg_nulls = palloc(sizeof(bool) * nargs);
2471+
scratch.d.json_constructor.arg_types = palloc(sizeof(Oid) * nargs);
2472+
scratch.d.json_constructor.nargs = nargs;
2473+
2474+
foreach(lc, args)
2475+
{
2476+
Expr *arg = (Expr *) lfirst(lc);
2477+
2478+
scratch.d.json_constructor.arg_types[argno] = exprType((Node *) arg);
2479+
2480+
if (IsA(arg, Const))
2481+
{
2482+
/* Don't evaluate const arguments every round */
2483+
Const *con = (Const *) arg;
2484+
2485+
scratch.d.json_constructor.arg_values[argno] = con->constvalue;
2486+
scratch.d.json_constructor.arg_nulls[argno] = con->constisnull;
2487+
}
2488+
else
2489+
{
2490+
ExecInitExprRec(arg, state,
2491+
&scratch.d.json_constructor.arg_values[argno],
2492+
&scratch.d.json_constructor.arg_nulls[argno]);
2493+
}
2494+
argno++;
2495+
}
2496+
2497+
ExprEvalPushStep(state, &scratch);
2498+
}
2499+
2500+
if (ctor->coercion)
2501+
{
2502+
Datum *innermost_caseval = state->innermost_caseval;
2503+
bool *innermost_isnull = state->innermost_casenull;
2504+
2505+
state->innermost_caseval = resv;
2506+
state->innermost_casenull = resnull;
2507+
2508+
ExecInitExprRec(ctor->coercion, state, resv, resnull);
2509+
2510+
state->innermost_caseval = innermost_caseval;
2511+
state->innermost_casenull = innermost_isnull;
2512+
}
2513+
}
2514+
break;
2515+
24532516
default:
24542517
elog(ERROR, "unrecognized node type: %d",
24552518
(int) nodeTag(node));

src/backend/executor/execExprInterp.c

+48
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
#include "utils/date.h"
7272
#include "utils/datum.h"
7373
#include "utils/expandedrecord.h"
74+
#include "utils/json.h"
75+
#include "utils/jsonb.h"
7476
#include "utils/lsyscache.h"
7577
#include "utils/memutils.h"
7678
#include "utils/timestamp.h"
@@ -477,6 +479,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
477479
&&CASE_EEOP_GROUPING_FUNC,
478480
&&CASE_EEOP_WINDOW_FUNC,
479481
&&CASE_EEOP_SUBPLAN,
482+
&&CASE_EEOP_JSON_CONSTRUCTOR,
480483
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
481484
&&CASE_EEOP_AGG_DESERIALIZE,
482485
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
@@ -1786,7 +1789,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
17861789
{
17871790
/* too complex for an inline implementation */
17881791
ExecEvalAggOrderedTransTuple(state, op, econtext);
1792+
EEO_NEXT();
1793+
}
17891794

1795+
EEO_CASE(EEOP_JSON_CONSTRUCTOR)
1796+
{
1797+
/* too complex for an inline implementation */
1798+
ExecEvalJsonConstructor(state, op, econtext);
17901799
EEO_NEXT();
17911800
}
17921801

@@ -4380,3 +4389,42 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
43804389

43814390
MemoryContextSwitchTo(oldContext);
43824391
}
4392+
4393+
/*
4394+
* Evaluate a JSON constructor expression.
4395+
*/
4396+
void
4397+
ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
4398+
ExprContext *econtext)
4399+
{
4400+
Datum res;
4401+
JsonConstructorExpr *ctor = op->d.json_constructor.constructor;
4402+
bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
4403+
bool isnull = false;
4404+
4405+
if (ctor->type == JSCTOR_JSON_ARRAY)
4406+
res = (is_jsonb ?
4407+
jsonb_build_array_worker :
4408+
json_build_array_worker)(op->d.json_constructor.nargs,
4409+
op->d.json_constructor.arg_values,
4410+
op->d.json_constructor.arg_nulls,
4411+
op->d.json_constructor.arg_types,
4412+
op->d.json_constructor.constructor->absent_on_null);
4413+
else if (ctor->type == JSCTOR_JSON_OBJECT)
4414+
res = (is_jsonb ?
4415+
jsonb_build_object_worker :
4416+
json_build_object_worker)(op->d.json_constructor.nargs,
4417+
op->d.json_constructor.arg_values,
4418+
op->d.json_constructor.arg_nulls,
4419+
op->d.json_constructor.arg_types,
4420+
op->d.json_constructor.constructor->absent_on_null,
4421+
op->d.json_constructor.constructor->unique);
4422+
else
4423+
{
4424+
res = (Datum) 0;
4425+
elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
4426+
}
4427+
4428+
*op->resvalue = res;
4429+
*op->resnull = isnull;
4430+
}

src/backend/jit/llvm/llvmjit_expr.c

+6
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,12 @@ llvm_compile_expr(ExprState *state)
23482348
LLVMBuildBr(b, opblocks[opno + 1]);
23492349
break;
23502350

2351+
case EEOP_JSON_CONSTRUCTOR:
2352+
build_EvalXFunc(b, mod, "ExecEvalJsonConstructor",
2353+
v_state, op, v_econtext);
2354+
LLVMBuildBr(b, opblocks[opno + 1]);
2355+
break;
2356+
23512357
case EEOP_LAST:
23522358
Assert(false);
23532359
break;

src/backend/jit/llvm/llvmjit_types.c

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ void *referenced_functions[] =
131131
ExecEvalSysVar,
132132
ExecEvalWholeRowVar,
133133
ExecEvalXmlExpr,
134+
ExecEvalJsonConstructor,
134135
MakeExpandedObjectReadOnlyInternal,
135136
slot_getmissingattrs,
136137
slot_getsomeattrs_int,

src/backend/nodes/copyfuncs.c

+173
Original file line numberDiff line numberDiff line change
@@ -2344,6 +2344,152 @@ _copyJsonValueExpr(const JsonValueExpr *from)
23442344
return newnode;
23452345
}
23462346

2347+
/*
2348+
* _copyJsonConstructorExpr
2349+
*/
2350+
static JsonConstructorExpr *
2351+
_copyJsonConstructorExpr(const JsonConstructorExpr *from)
2352+
{
2353+
JsonConstructorExpr *newnode = makeNode(JsonConstructorExpr);
2354+
2355+
COPY_SCALAR_FIELD(type);
2356+
COPY_NODE_FIELD(args);
2357+
COPY_NODE_FIELD(func);
2358+
COPY_NODE_FIELD(coercion);
2359+
COPY_NODE_FIELD(returning);
2360+
COPY_SCALAR_FIELD(absent_on_null);
2361+
COPY_SCALAR_FIELD(unique);
2362+
COPY_LOCATION_FIELD(location);
2363+
2364+
return newnode;
2365+
}
2366+
2367+
/*
2368+
* _copyJsonKeyValue
2369+
*/
2370+
static JsonKeyValue *
2371+
_copyJsonKeyValue(const JsonKeyValue *from)
2372+
{
2373+
JsonKeyValue *newnode = makeNode(JsonKeyValue);
2374+
2375+
COPY_NODE_FIELD(key);
2376+
COPY_NODE_FIELD(value);
2377+
2378+
return newnode;
2379+
}
2380+
2381+
/*
2382+
* _copyJsonObjectConstructor
2383+
*/
2384+
static JsonObjectConstructor *
2385+
_copyJsonObjectConstructor(const JsonObjectConstructor *from)
2386+
{
2387+
JsonObjectConstructor *newnode = makeNode(JsonObjectConstructor);
2388+
2389+
COPY_NODE_FIELD(exprs);
2390+
COPY_NODE_FIELD(output);
2391+
COPY_SCALAR_FIELD(absent_on_null);
2392+
COPY_SCALAR_FIELD(unique);
2393+
COPY_LOCATION_FIELD(location);
2394+
2395+
return newnode;
2396+
}
2397+
2398+
/*
2399+
* _copyJsonAggConstructor
2400+
*/
2401+
static JsonAggConstructor *
2402+
_copyJsonAggConstructor(const JsonAggConstructor *from)
2403+
{
2404+
JsonAggConstructor *newnode = makeNode(JsonAggConstructor);
2405+
2406+
COPY_NODE_FIELD(output);
2407+
COPY_NODE_FIELD(agg_filter);
2408+
COPY_NODE_FIELD(agg_order);
2409+
COPY_NODE_FIELD(over);
2410+
COPY_LOCATION_FIELD(location);
2411+
2412+
return newnode;
2413+
}
2414+
2415+
/*
2416+
* _copyJsonObjectAgg
2417+
*/
2418+
static JsonObjectAgg *
2419+
_copyJsonObjectAgg(const JsonObjectAgg *from)
2420+
{
2421+
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
2422+
2423+
COPY_NODE_FIELD(constructor);
2424+
COPY_NODE_FIELD(arg);
2425+
COPY_SCALAR_FIELD(absent_on_null);
2426+
COPY_SCALAR_FIELD(unique);
2427+
2428+
return newnode;
2429+
}
2430+
2431+
/*
2432+
* _copyJsonOutput
2433+
*/
2434+
static JsonOutput *
2435+
_copyJsonOutput(const JsonOutput *from)
2436+
{
2437+
JsonOutput *newnode = makeNode(JsonOutput);
2438+
2439+
COPY_NODE_FIELD(typeName);
2440+
COPY_NODE_FIELD(returning);
2441+
2442+
return newnode;
2443+
}
2444+
2445+
/*
2446+
* _copyJsonArrayConstructor
2447+
*/
2448+
static JsonArrayConstructor *
2449+
_copyJsonArrayConstructor(const JsonArrayConstructor *from)
2450+
{
2451+
JsonArrayConstructor *newnode = makeNode(JsonArrayConstructor);
2452+
2453+
COPY_NODE_FIELD(exprs);
2454+
COPY_NODE_FIELD(output);
2455+
COPY_SCALAR_FIELD(absent_on_null);
2456+
COPY_LOCATION_FIELD(location);
2457+
2458+
return newnode;
2459+
}
2460+
2461+
/*
2462+
* _copyJsonArrayAgg
2463+
*/
2464+
static JsonArrayAgg *
2465+
_copyJsonArrayAgg(const JsonArrayAgg *from)
2466+
{
2467+
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
2468+
2469+
COPY_NODE_FIELD(constructor);
2470+
COPY_NODE_FIELD(arg);
2471+
COPY_SCALAR_FIELD(absent_on_null);
2472+
2473+
return newnode;
2474+
}
2475+
2476+
/*
2477+
* _copyJsonArrayQueryConstructor
2478+
*/
2479+
static JsonArrayQueryConstructor *
2480+
_copyJsonArrayQueryConstructor(const JsonArrayQueryConstructor *from)
2481+
{
2482+
JsonArrayQueryConstructor *newnode = makeNode(JsonArrayQueryConstructor);
2483+
2484+
COPY_NODE_FIELD(query);
2485+
COPY_NODE_FIELD(output);
2486+
COPY_NODE_FIELD(format);
2487+
COPY_SCALAR_FIELD(absent_on_null);
2488+
COPY_LOCATION_FIELD(location);
2489+
2490+
return newnode;
2491+
}
2492+
23472493
/* ****************************************************************
23482494
* pathnodes.h copy functions
23492495
*
@@ -5406,6 +5552,33 @@ copyObjectImpl(const void *from)
54065552
case T_JsonValueExpr:
54075553
retval = _copyJsonValueExpr(from);
54085554
break;
5555+
case T_JsonKeyValue:
5556+
retval = _copyJsonKeyValue(from);
5557+
break;
5558+
case T_JsonConstructorExpr:
5559+
retval = _copyJsonConstructorExpr(from);
5560+
break;
5561+
case T_JsonObjectConstructor:
5562+
retval = _copyJsonObjectConstructor(from);
5563+
break;
5564+
case T_JsonAggConstructor:
5565+
retval = _copyJsonAggConstructor(from);
5566+
break;
5567+
case T_JsonObjectAgg:
5568+
retval = _copyJsonObjectAgg(from);
5569+
break;
5570+
case T_JsonOutput:
5571+
retval = _copyJsonOutput(from);
5572+
break;
5573+
case T_JsonArrayConstructor:
5574+
retval = _copyJsonArrayConstructor(from);
5575+
break;
5576+
case T_JsonArrayQueryConstructor:
5577+
retval = _copyJsonArrayQueryConstructor(from);
5578+
break;
5579+
case T_JsonArrayAgg:
5580+
retval = _copyJsonArrayAgg(from);
5581+
break;
54095582

54105583
/*
54115584
* RELATION NODES

0 commit comments

Comments
 (0)