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

Commit 6bfeaf4

Browse files
author
Nikita Glukhov
committed
Add subtransactions for JsonExpr execution
1 parent 86aba60 commit 6bfeaf4

File tree

4 files changed

+173
-2
lines changed

4 files changed

+173
-2
lines changed

src/backend/executor/execExpr.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,6 +2123,9 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
21232123
}
21242124
}
21252125

2126+
if (jexpr->on_error.btype != JSON_BEHAVIOR_ERROR)
2127+
scratch.d.jsonexpr.volatility = getJsonExprVolatility(jexpr);
2128+
21262129
ExprEvalPushStep(state, &scratch);
21272130
}
21282131
break;

src/backend/executor/execExprInterp.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
#include "postgres.h"
6060

6161
#include "access/tuptoaster.h"
62+
#include "access/xact.h"
63+
#include "catalog/pg_proc.h"
6264
#include "catalog/pg_type.h"
6365
#include "commands/sequence.h"
6466
#include "executor/execExpr.h"
@@ -76,6 +78,7 @@
7678
#include "utils/jsonb.h"
7779
#include "utils/jsonpath.h"
7880
#include "utils/lsyscache.h"
81+
#include "utils/resowner.h"
7982
#include "utils/timestamp.h"
8083
#include "utils/typcache.h"
8184
#include "utils/xml.h"
@@ -3992,18 +3995,63 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39923995

39933996
if (jexpr->on_error.btype == JSON_BEHAVIOR_ERROR)
39943997
{
3995-
/* No need to use PG_TRY/PG_CATCH. */
3998+
/* No need to use PG_TRY/PG_CATCH with subtransactions. */
39963999
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item, isjsonb,
39974000
op->resnull);
39984001
}
39994002
else
40004003
{
4004+
/*
4005+
* We should catch exceptions of category ERRCODE_DATA_EXCEPTION and
4006+
* execute corresponding ON ERROR behavior.
4007+
*/
4008+
char volatility = op->d.jsonexpr.volatility;
4009+
bool useSubTransaction = volatility == PROVOLATILE_VOLATILE;
4010+
bool useSubResourceOwner = volatility == PROVOLATILE_STABLE;
40014011
MemoryContext oldcontext = CurrentMemoryContext;
4012+
ResourceOwner oldowner = CurrentResourceOwner;
4013+
4014+
if (useSubTransaction)
4015+
{
4016+
BeginInternalSubTransaction(NULL);
4017+
/* Want to execute expressions inside function's memory context */
4018+
MemoryContextSwitchTo(oldcontext);
4019+
}
4020+
else if (useSubResourceOwner)
4021+
{
4022+
CurrentResourceOwner = ResourceOwnerCreate(CurrentResourceOwner,
4023+
"JsonExpr");
4024+
}
40024025

40034026
PG_TRY();
40044027
{
4005-
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item,
4028+
/*
4029+
* We need to execute expressions with a new econtext
4030+
* that belongs to the current subtransaction; if we try to use
4031+
* the outer econtext then ExprContext shutdown callbacks will be
4032+
* called at the wrong times.
4033+
*/
4034+
ExprContext *newecontext = useSubTransaction ?
4035+
CreateExprContext(econtext->ecxt_estate) : econtext;
4036+
4037+
res = ExecEvalJsonExpr(state, op, newecontext, jexpr, path, item,
40064038
isjsonb, op->resnull);
4039+
4040+
if (useSubTransaction)
4041+
{
4042+
/* Commit the inner transaction, return to outer xact context */
4043+
ReleaseCurrentSubTransaction();
4044+
MemoryContextSwitchTo(oldcontext);
4045+
CurrentResourceOwner = oldowner;
4046+
}
4047+
else if (useSubResourceOwner)
4048+
{
4049+
/* buffer pins are released here: */
4050+
ResourceOwnerRelease(CurrentResourceOwner,
4051+
RESOURCE_RELEASE_BEFORE_LOCKS,
4052+
false, true);
4053+
CurrentResourceOwner = oldowner;
4054+
}
40074055
}
40084056
PG_CATCH();
40094057
{
@@ -4014,6 +4062,22 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40144062
edata = CopyErrorData();
40154063
FlushErrorState();
40164064

4065+
if (useSubTransaction)
4066+
{
4067+
/* Abort the inner transaction */
4068+
RollbackAndReleaseCurrentSubTransaction();
4069+
MemoryContextSwitchTo(oldcontext);
4070+
CurrentResourceOwner = oldowner;
4071+
}
4072+
else if (useSubResourceOwner)
4073+
{
4074+
/* buffer pins are released here: */
4075+
ResourceOwnerRelease(CurrentResourceOwner,
4076+
RESOURCE_RELEASE_BEFORE_LOCKS,
4077+
false, true);
4078+
CurrentResourceOwner = oldowner;
4079+
}
4080+
40174081
if (ERRCODE_TO_CATEGORY(edata->sqlerrcode) != ERRCODE_DATA_EXCEPTION)
40184082
ReThrowError(edata);
40194083

src/backend/parser/parse_expr.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "miscadmin.h"
2323
#include "nodes/makefuncs.h"
2424
#include "nodes/nodeFuncs.h"
25+
#include "optimizer/clauses.h"
2526
#include "optimizer/tlist.h"
2627
#include "optimizer/var.h"
2728
#include "parser/analyze.h"
@@ -4717,3 +4718,105 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
47174718

47184719
return (Node *) jsexpr;
47194720
}
4721+
4722+
static char
4723+
getExprVolatility(Node *expr)
4724+
{
4725+
if (contain_volatile_functions(expr))
4726+
return PROVOLATILE_VOLATILE;
4727+
4728+
if (contain_mutable_functions(expr))
4729+
return PROVOLATILE_STABLE;
4730+
4731+
return PROVOLATILE_IMMUTABLE;
4732+
}
4733+
4734+
static char
4735+
getJsonCoercionVolatility(JsonCoercion *coercion, JsonReturning *returning)
4736+
{
4737+
if (!coercion)
4738+
return PROVOLATILE_IMMUTABLE;
4739+
4740+
if (coercion->expr)
4741+
return getExprVolatility(coercion->expr);
4742+
4743+
if (coercion->via_io)
4744+
{
4745+
Oid typinput;
4746+
Oid typioparam;
4747+
4748+
getTypeInputInfo(returning->typid, &typinput, &typioparam);
4749+
4750+
return func_volatile(typinput);
4751+
}
4752+
4753+
if (coercion->via_populate)
4754+
return PROVOLATILE_STABLE;
4755+
4756+
return PROVOLATILE_IMMUTABLE;
4757+
}
4758+
4759+
char
4760+
getJsonExprVolatility(JsonExpr *jsexpr)
4761+
{
4762+
char volatility;
4763+
char volatility2;
4764+
ListCell *lc;
4765+
4766+
volatility = getExprVolatility(jsexpr->formatted_expr);
4767+
4768+
if (volatility == PROVOLATILE_VOLATILE)
4769+
return PROVOLATILE_VOLATILE;
4770+
4771+
volatility2 = getJsonCoercionVolatility(jsexpr->result_coercion,
4772+
&jsexpr->returning);
4773+
4774+
if (volatility2 == PROVOLATILE_VOLATILE)
4775+
return PROVOLATILE_VOLATILE;
4776+
4777+
if (volatility2 == PROVOLATILE_STABLE)
4778+
volatility = PROVOLATILE_STABLE;
4779+
4780+
if (jsexpr->coercions)
4781+
{
4782+
JsonCoercion **coercion;
4783+
4784+
for (coercion = &jsexpr->coercions->null;
4785+
coercion <= &jsexpr->coercions->composite;
4786+
coercion++)
4787+
{
4788+
volatility2 = getJsonCoercionVolatility(*coercion, &jsexpr->returning);
4789+
4790+
if (volatility2 == PROVOLATILE_VOLATILE)
4791+
return PROVOLATILE_VOLATILE;
4792+
4793+
if (volatility2 == PROVOLATILE_STABLE)
4794+
volatility = PROVOLATILE_STABLE;
4795+
}
4796+
}
4797+
4798+
if (jsexpr->on_empty.btype == JSON_BEHAVIOR_DEFAULT)
4799+
{
4800+
volatility2 = getExprVolatility(jsexpr->on_empty.default_expr);
4801+
4802+
if (volatility2 == PROVOLATILE_VOLATILE)
4803+
return PROVOLATILE_VOLATILE;
4804+
4805+
if (volatility2 == PROVOLATILE_STABLE)
4806+
volatility = PROVOLATILE_STABLE;
4807+
}
4808+
4809+
foreach(lc, jsexpr->passing.values)
4810+
{
4811+
volatility2 = getExprVolatility(lfirst(lc));
4812+
4813+
if (volatility2 == PROVOLATILE_VOLATILE)
4814+
return PROVOLATILE_VOLATILE;
4815+
4816+
if (volatility2 == PROVOLATILE_STABLE)
4817+
volatility = PROVOLATILE_STABLE;
4818+
}
4819+
4820+
return volatility;
4821+
}
4822+

src/include/executor/execExpr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,7 @@ typedef struct ExprEvalStep
567567
struct
568568
{
569569
JsonExpr *jsexpr; /* original expression node */
570+
char volatility; /* volatility of subexpressions */
570571

571572
struct
572573
{

0 commit comments

Comments
 (0)