SQL/JSON: Fix error-handling of some JsonBehavior expressions
To ensure that the errors of executing a JsonBehavior expression that is coerced in the parser are caught instead of being thrown directly, pass ErrorSaveContext to ExecInitExprRec() when initializing it. Also, add a EEOP_JSONEXPR_COERCION_FINISH step to handle the errors that are caught that way. Discussion: https://postgr.es/m/CACJufxEo4sUjKCYtda0_qt9tazqqKPmF1cqhW9KBOUeJFqQd2g@mail.gmail.com Backpatch-through: 17
This commit is contained in:
parent
c7301c3b6f
commit
63e6c5f4a2
@ -4400,6 +4400,8 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
|
||||
if (jsexpr->on_error &&
|
||||
jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR)
|
||||
{
|
||||
ErrorSaveContext *saved_escontext;
|
||||
|
||||
jsestate->jump_error = state->steps_len;
|
||||
|
||||
/* JUMP to end if false, that is, skip the ON ERROR expression. */
|
||||
@ -4410,15 +4412,36 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
|
||||
scratch->d.jump.jumpdone = -1; /* set below */
|
||||
ExprEvalPushStep(state, scratch);
|
||||
|
||||
/* Steps to evaluate the ON ERROR expression */
|
||||
/*
|
||||
* Steps to evaluate the ON ERROR expression; handle errors softly to
|
||||
* rethrow them in COERCION_FINISH step that will be added later.
|
||||
*/
|
||||
saved_escontext = state->escontext;
|
||||
state->escontext = escontext;
|
||||
ExecInitExprRec((Expr *) jsexpr->on_error->expr,
|
||||
state, resv, resnull);
|
||||
state->escontext = saved_escontext;
|
||||
|
||||
/* Step to coerce the ON ERROR expression if needed */
|
||||
if (jsexpr->on_error->coerce)
|
||||
ExecInitJsonCoercion(state, jsexpr->returning, escontext,
|
||||
jsexpr->omit_quotes, resv, resnull);
|
||||
|
||||
/*
|
||||
* Add a COERCION_FINISH step to check for errors that may occur when
|
||||
* coercing and rethrow them.
|
||||
*/
|
||||
if (jsexpr->on_error->coerce ||
|
||||
IsA(jsexpr->on_error->expr, CoerceViaIO) ||
|
||||
IsA(jsexpr->on_error->expr, CoerceToDomain))
|
||||
{
|
||||
scratch->opcode = EEOP_JSONEXPR_COERCION_FINISH;
|
||||
scratch->resvalue = resv;
|
||||
scratch->resnull = resnull;
|
||||
scratch->d.jsonexpr.jsestate = jsestate;
|
||||
ExprEvalPushStep(state, scratch);
|
||||
}
|
||||
|
||||
/* JUMP to end to skip the ON EMPTY steps added below. */
|
||||
jumps_to_end = lappend_int(jumps_to_end, state->steps_len);
|
||||
scratch->opcode = EEOP_JUMP;
|
||||
@ -4433,6 +4456,8 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
|
||||
if (jsexpr->on_empty != NULL &&
|
||||
jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR)
|
||||
{
|
||||
ErrorSaveContext *saved_escontext;
|
||||
|
||||
jsestate->jump_empty = state->steps_len;
|
||||
|
||||
/* JUMP to end if false, that is, skip the ON EMPTY expression. */
|
||||
@ -4443,14 +4468,36 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state,
|
||||
scratch->d.jump.jumpdone = -1; /* set below */
|
||||
ExprEvalPushStep(state, scratch);
|
||||
|
||||
/* Steps to evaluate the ON EMPTY expression */
|
||||
/*
|
||||
* Steps to evaluate the ON EMPTY expression; handle errors softly to
|
||||
* rethrow them in COERCION_FINISH step that will be added later.
|
||||
*/
|
||||
saved_escontext = state->escontext;
|
||||
state->escontext = escontext;
|
||||
ExecInitExprRec((Expr *) jsexpr->on_empty->expr,
|
||||
state, resv, resnull);
|
||||
state->escontext = saved_escontext;
|
||||
|
||||
/* Step to coerce the ON EMPTY expression if needed */
|
||||
if (jsexpr->on_empty->coerce)
|
||||
ExecInitJsonCoercion(state, jsexpr->returning, escontext,
|
||||
jsexpr->omit_quotes, resv, resnull);
|
||||
|
||||
/*
|
||||
* Add a COERCION_FINISH step to check for errors that may occur when
|
||||
* coercing and rethrow them.
|
||||
*/
|
||||
if (jsexpr->on_empty->coerce ||
|
||||
IsA(jsexpr->on_empty->expr, CoerceViaIO) ||
|
||||
IsA(jsexpr->on_empty->expr, CoerceToDomain))
|
||||
{
|
||||
|
||||
scratch->opcode = EEOP_JSONEXPR_COERCION_FINISH;
|
||||
scratch->resvalue = resv;
|
||||
scratch->resnull = resnull;
|
||||
scratch->d.jsonexpr.jsestate = jsestate;
|
||||
ExprEvalPushStep(state, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
foreach(lc, jumps_to_end)
|
||||
|
@ -4558,6 +4558,12 @@ ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op)
|
||||
*op->resvalue = (Datum) 0;
|
||||
*op->resnull = true;
|
||||
jsestate->error.value = BoolGetDatum(true);
|
||||
|
||||
/*
|
||||
* Reset for next use such as for catching errors when coercing a
|
||||
* JsonBehavior expression.
|
||||
*/
|
||||
jsestate->escontext.error_occurred = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,7 +227,11 @@ SELECT * FROM JSON_TABLE(jsonb '{"d1": "H"}', '$'
|
||||
|
||||
SELECT * FROM JSON_TABLE(jsonb '{"d1": "H"}', '$'
|
||||
COLUMNS (js1 jsonb_test_domain PATH '$.a2' DEFAULT 'foo'::jsonb_test_domain ON EMPTY));
|
||||
ERROR: value for domain jsonb_test_domain violates check constraint "jsonb_test_domain_check"
|
||||
js1
|
||||
-----
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT * FROM JSON_TABLE(jsonb '{"d1": "H"}', '$'
|
||||
COLUMNS (js1 jsonb_test_domain PATH '$.a2' DEFAULT 'foo1'::jsonb_test_domain ON EMPTY));
|
||||
js1
|
||||
|
@ -1232,7 +1232,11 @@ DROP TABLE test_jsonb_mutability;
|
||||
DROP FUNCTION ret_setint;
|
||||
CREATE DOMAIN queryfuncs_test_domain AS text CHECK (value <> 'foo');
|
||||
SELECT JSON_VALUE(jsonb '{"d1": "H"}', '$.a2' RETURNING queryfuncs_test_domain DEFAULT 'foo'::queryfuncs_test_domain ON EMPTY);
|
||||
ERROR: value for domain queryfuncs_test_domain violates check constraint "queryfuncs_test_domain_check"
|
||||
json_value
|
||||
------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT JSON_VALUE(jsonb '{"d1": "H"}', '$.a2' RETURNING queryfuncs_test_domain DEFAULT 'foo1'::queryfuncs_test_domain ON EMPTY);
|
||||
json_value
|
||||
------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user