Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9fb0b79

Browse files
author
Nikita Glukhov
committed
Add JSON_TRANSFORM()
1 parent740222f commit9fb0b79

File tree

22 files changed

+2239
-67
lines changed

22 files changed

+2239
-67
lines changed

‎src/backend/catalog/system_functions.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,15 @@ LANGUAGE INTERNAL
579579
STRICT STABLE PARALLEL SAFE
580580
AS'jsonb_path_query_first_tz';
581581

582+
CREATEOR REPLACE FUNCTION
583+
jsonb_path_set(target jsonb,path jsonpath, newval jsonb,
584+
vars jsonb DEFAULT'{}',
585+
silentboolean DEFAULT false)
586+
RETURNS jsonb
587+
LANGUAGE INTERNAL
588+
IMMUTABLE PARALLEL SAFE
589+
AS'jsonb_path_set';
590+
582591
-- default normalization form is NFC, per SQL standard
583592
CREATEOR REPLACE FUNCTION
584593
"normalize"(text,text DEFAULT'NFC')

‎src/backend/executor/execExpr.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2668,6 +2668,101 @@ ExecInitExprRec(Expr *node, ExprState *state,
26682668
break;
26692669
}
26702670

2671+
caseT_JsonTransformExpr:
2672+
{
2673+
JsonTransformExpr*jexpr=castNode(JsonTransformExpr,node);
2674+
ListCell*argexprlc;
2675+
ListCell*argnamelc;
2676+
ListCell*oplc;
2677+
inti=0;
2678+
2679+
scratch.opcode=EEOP_JSONTRANSFORM;
2680+
scratch.d.jsontransform.jsexpr=jexpr;
2681+
2682+
scratch.d.jsontransform.formatted_expr=
2683+
palloc(sizeof(*scratch.d.jsontransform.formatted_expr));
2684+
2685+
ExecInitExprRec((Expr*)jexpr->formatted_expr,state,
2686+
&scratch.d.jsontransform.formatted_expr->value,
2687+
&scratch.d.jsontransform.formatted_expr->isnull);
2688+
2689+
scratch.d.jsontransform.ops=
2690+
palloc(sizeof(*scratch.d.jsontransform.ops)*list_length(jexpr->ops));
2691+
2692+
foreach(oplc,jexpr->ops)
2693+
{
2694+
JsonTransformOp*op=lfirst_node(JsonTransformOp,oplc);
2695+
2696+
if (op->expr)
2697+
{
2698+
ExecInitExprRec((Expr*)op->expr,state,
2699+
&scratch.d.jsontransform.ops[i].expr.value,
2700+
&scratch.d.jsontransform.ops[i].expr.isnull);
2701+
2702+
scratch.d.jsontransform.ops[i].expr_typid=exprType(op->expr);
2703+
scratch.d.jsontransform.ops[i].expr_typmod=exprTypmod(op->expr);
2704+
}
2705+
else
2706+
{
2707+
memset(&scratch.d.jsontransform.ops[i],0,
2708+
sizeof(scratch.d.jsontransform.ops[i]));
2709+
scratch.d.jsontransform.ops[i].expr.isnull= true;
2710+
}
2711+
2712+
ExecInitExprRec((Expr*)op->pathspec,state,
2713+
&scratch.d.jsontransform.ops[i].pathspec.value,
2714+
&scratch.d.jsontransform.ops[i].pathspec.isnull);
2715+
2716+
i++;
2717+
}
2718+
2719+
scratch.d.jsontransform.res_expr=
2720+
palloc(sizeof(*scratch.d.jsontransform.res_expr));
2721+
2722+
scratch.d.jsontransform.result_expr=jexpr->result_coercion
2723+
?ExecInitExprWithCaseValue((Expr*)jexpr->result_coercion->expr,
2724+
state->parent,
2725+
&scratch.d.jsontransform.res_expr->value,
2726+
&scratch.d.jsontransform.res_expr->isnull)
2727+
:NULL;
2728+
2729+
if (jexpr->result_coercion&&jexpr->result_coercion->via_io)
2730+
{
2731+
Oidtypinput;
2732+
2733+
/* lookup the result type's input function */
2734+
getTypeInputInfo(jexpr->returning->typid,&typinput,
2735+
&scratch.d.jsontransform.input.typioparam);
2736+
fmgr_info(typinput,&scratch.d.jsontransform.input.func);
2737+
}
2738+
2739+
scratch.d.jsontransform.args=NIL;
2740+
2741+
forboth(argexprlc,jexpr->passing_values,
2742+
argnamelc,jexpr->passing_names)
2743+
{
2744+
Expr*argexpr= (Expr*)lfirst(argexprlc);
2745+
String*argname=lfirst_node(String,argnamelc);
2746+
JsonPathVariableEvalContext*var=palloc(sizeof(*var));
2747+
2748+
var->name=pstrdup(argname->sval);
2749+
var->typid=exprType((Node*)argexpr);
2750+
var->typmod=exprTypmod((Node*)argexpr);
2751+
var->estate=ExecInitExpr(argexpr,state->parent);
2752+
var->econtext=NULL;
2753+
var->mcxt=NULL;
2754+
var->evaluated= false;
2755+
var->value= (Datum)0;
2756+
var->isnull= true;
2757+
2758+
scratch.d.jsontransform.args=
2759+
lappend(scratch.d.jsontransform.args,var);
2760+
}
2761+
2762+
ExprEvalPushStep(state,&scratch);
2763+
break;
2764+
}
2765+
26712766
default:
26722767
elog(ERROR,"unrecognized node type: %d",
26732768
(int)nodeTag(node));

‎src/backend/executor/execExprInterp.c

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
491491
&&CASE_EEOP_JSON_CONSTRUCTOR,
492492
&&CASE_EEOP_IS_JSON,
493493
&&CASE_EEOP_JSONEXPR,
494+
&&CASE_EEOP_JSONTRANSFORM,
494495
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
495496
&&CASE_EEOP_AGG_DESERIALIZE,
496497
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
@@ -1824,6 +1825,13 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
18241825
EEO_NEXT();
18251826
}
18261827

1828+
EEO_CASE(EEOP_JSONTRANSFORM)
1829+
{
1830+
/* too complex for an inline implementation */
1831+
ExecEvalJsonTransform(state,op,econtext);
1832+
EEO_NEXT();
1833+
}
1834+
18271835
EEO_CASE(EEOP_LAST)
18281836
{
18291837
/* unreachable */
@@ -5143,3 +5151,111 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
51435151

51445152
*op->resvalue=res;
51455153
}
5154+
5155+
/*
5156+
* Evaluate a coercion of a JSON item to the target type.
5157+
*/
5158+
staticDatum
5159+
ExecEvalJsonTransformCoercion(ExprEvalStep*op,ExprContext*econtext,
5160+
Datumres,bool*isNull)
5161+
{
5162+
JsonTransformExpr*jexpr=op->d.jsontransform.jsexpr;
5163+
JsonCoercion*coercion=jexpr->result_coercion;
5164+
5165+
if (coercion)
5166+
{
5167+
if (coercion->via_io)
5168+
{
5169+
/* strip quotes and call typinput function */
5170+
char*str=*isNull ?NULL :JsonbUnquote(DatumGetJsonbP(res));
5171+
5172+
returnInputFunctionCall(&op->d.jsontransform.input.func,str,
5173+
op->d.jsontransform.input.typioparam,
5174+
jexpr->returning->typmod);
5175+
}
5176+
5177+
if (coercion->via_populate)
5178+
returnjson_populate_type(res,JSONBOID,
5179+
jexpr->returning->typid,
5180+
jexpr->returning->typmod,
5181+
&op->d.jsontransform.cache,
5182+
econtext->ecxt_per_query_memory,
5183+
isNull);
5184+
}
5185+
5186+
if (op->d.jsontransform.result_expr)
5187+
{
5188+
op->d.jsontransform.res_expr->value=res;
5189+
op->d.jsontransform.res_expr->isnull=*isNull;
5190+
5191+
res=ExecEvalExpr(op->d.jsontransform.result_expr,econtext,isNull);
5192+
}
5193+
5194+
returnres;
5195+
}
5196+
5197+
void
5198+
ExecEvalJsonTransform(ExprState*state,ExprEvalStep*op,ExprContext*econtext)
5199+
{
5200+
JsonTransformExpr*jexpr=op->d.jsontransform.jsexpr;
5201+
Datumres= (Datum)0;
5202+
ListCell*lc;
5203+
inti=0;
5204+
5205+
*op->resnull= true;/* until we get a result */
5206+
*op->resvalue= (Datum)0;
5207+
5208+
if (op->d.jsontransform.formatted_expr->isnull)
5209+
gotocheck_null;
5210+
5211+
res=op->d.jsontransform.formatted_expr->value;
5212+
5213+
/* reset JSON path variable contexts */
5214+
foreach(lc,op->d.jsontransform.args)
5215+
{
5216+
JsonPathVariableEvalContext*var=lfirst(lc);
5217+
5218+
var->econtext=econtext;
5219+
var->evaluated= false;
5220+
}
5221+
5222+
foreach(lc,jexpr->ops)
5223+
{
5224+
JsonPath*path;
5225+
JsonTransformOp*oper=lfirst_node(JsonTransformOp,lc);
5226+
5227+
if (op->d.jsontransform.ops[i].pathspec.isnull)
5228+
gotocheck_null;
5229+
5230+
if (oper->on_null==JSTB_ERROR&&
5231+
op->d.jsontransform.ops[i].expr.isnull)
5232+
ereport(ERROR,
5233+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5234+
errmsg("JSON_TRANSFORM called with NULL input")));
5235+
5236+
path=DatumGetJsonPathP(op->d.jsontransform.ops[i].pathspec.value);
5237+
res=JsonPathTransform(res,path,
5238+
op->d.jsontransform.ops[i].expr.value,
5239+
op->d.jsontransform.ops[i].expr.isnull,
5240+
op->d.jsontransform.ops[i].expr_typid,
5241+
op->d.jsontransform.ops[i].expr_typmod,
5242+
op->d.jsontransform.args,
5243+
oper->op_type,oper->on_existing,
5244+
oper->on_missing,oper->on_null);
5245+
5246+
*op->resnull=res== (Datum)0;
5247+
5248+
if (*op->resnull)
5249+
gotocheck_null;
5250+
5251+
i++;
5252+
}
5253+
5254+
*op->resvalue=ExecEvalJsonTransformCoercion(op,econtext,res,op->resnull);
5255+
return;
5256+
5257+
check_null:
5258+
/* execute domain checks for NULLs */
5259+
(void)ExecEvalJsonTransformCoercion(op,econtext,res,op->resnull);
5260+
Assert(*op->resnull);
5261+
}

‎src/backend/nodes/makefuncs.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,3 +941,29 @@ makeJsonIsPredicate(Node *expr, JsonFormat *format, JsonValueType item_type,
941941

942942
return (Node*)n;
943943
}
944+
945+
/*
946+
* makeJsonTransformOp -
947+
* creates a JsonTransformOp node
948+
*/
949+
Node*
950+
makeJsonTransformOp(JsonTransformOpTypeop_type,
951+
Node*pathspec,Node*expr,
952+
JsonTransformBehavioron_existing,
953+
JsonTransformBehavioron_missing,
954+
JsonTransformBehavioron_null,
955+
intlocation)
956+
{
957+
JsonTransformOp*n=makeNode(JsonTransformOp);
958+
959+
n->pathspec=pathspec;
960+
n->expr=expr;
961+
n->op_type=op_type;
962+
n->on_existing=on_existing;
963+
n->on_missing=on_missing;
964+
n->on_null=on_null;
965+
n->location=location;
966+
967+
return (Node*)n;
968+
}
969+

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp