57
57
#include "postgres.h"
58
58
59
59
#include "access/heaptoast.h"
60
+ #include "access/xact.h"
61
+ #include "catalog/pg_proc.h"
60
62
#include "catalog/pg_type.h"
61
63
#include "commands/sequence.h"
62
64
#include "executor/execExpr.h"
79
81
#include "utils/jsonpath.h"
80
82
#include "utils/lsyscache.h"
81
83
#include "utils/memutils.h"
84
+ #include "utils/resowner.h"
82
85
#include "utils/timestamp.h"
83
86
#include "utils/typcache.h"
84
87
#include "utils/xml.h"
@@ -4816,6 +4819,12 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
4816
4819
return res ;
4817
4820
}
4818
4821
4822
+ bool
4823
+ ExecEvalJsonNeedsSubTransaction (JsonExpr * jsexpr )
4824
+ {
4825
+ return jsexpr -> on_error -> btype != JSON_BEHAVIOR_ERROR ;
4826
+ }
4827
+
4819
4828
/* ----------------------------------------------------------------
4820
4829
* ExecEvalJson
4821
4830
* ----------------------------------------------------------------
@@ -4855,20 +4864,34 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
4855
4864
var -> evaluated = false;
4856
4865
}
4857
4866
4858
- if (jexpr -> on_error -> btype == JSON_BEHAVIOR_ERROR )
4867
+ if (! ExecEvalJsonNeedsSubTransaction ( jexpr ) )
4859
4868
{
4860
4869
/* No need to use PG_TRY/PG_CATCH with subtransactions. */
4861
4870
res = ExecEvalJsonExpr (state , op , econtext , jexpr , path , item ,
4862
4871
op -> resnull );
4863
4872
}
4864
4873
else
4865
4874
{
4875
+ /*
4876
+ * We should catch exceptions of category ERRCODE_DATA_EXCEPTION and
4877
+ * execute corresponding ON ERROR behavior.
4878
+ */
4866
4879
MemoryContext oldcontext = CurrentMemoryContext ;
4880
+ ResourceOwner oldowner = CurrentResourceOwner ;
4881
+
4882
+ BeginInternalSubTransaction (NULL );
4883
+ /* Want to execute expressions inside function's memory context */
4884
+ MemoryContextSwitchTo (oldcontext );
4867
4885
4868
4886
PG_TRY ();
4869
4887
{
4870
4888
res = ExecEvalJsonExpr (state , op , econtext , jexpr , path , item ,
4871
4889
op -> resnull );
4890
+
4891
+ /* Commit the inner transaction, return to outer xact context */
4892
+ ReleaseCurrentSubTransaction ();
4893
+ MemoryContextSwitchTo (oldcontext );
4894
+ CurrentResourceOwner = oldowner ;
4872
4895
}
4873
4896
PG_CATCH ();
4874
4897
{
@@ -4879,6 +4902,11 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
4879
4902
edata = CopyErrorData ();
4880
4903
FlushErrorState ();
4881
4904
4905
+ /* Abort the inner transaction */
4906
+ RollbackAndReleaseCurrentSubTransaction ();
4907
+ MemoryContextSwitchTo (oldcontext );
4908
+ CurrentResourceOwner = oldowner ;
4909
+
4882
4910
if (ERRCODE_TO_CATEGORY (edata -> sqlerrcode ) != ERRCODE_DATA_EXCEPTION )
4883
4911
ReThrowError (edata );
4884
4912
0 commit comments