diff options
Diffstat (limited to 'src/backend/executor/execExprInterp.c')
-rw-r--r-- | src/backend/executor/execExprInterp.c | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 4c9b2a8c178..430438f668e 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -4284,13 +4284,12 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, memset(&jsestate->error, 0, sizeof(NullableDatum)); memset(&jsestate->empty, 0, sizeof(NullableDatum)); - /* - * Also reset ErrorSaveContext contents for the next row. Since we don't - * set details_wanted, we don't need to also reset error_data, which would - * be NULL anyway. - */ - Assert(!jsestate->escontext.details_wanted && - jsestate->escontext.error_data == NULL); + /* Also reset ErrorSaveContext contents for the next row. */ + if (jsestate->escontext.details_wanted) + { + jsestate->escontext.error_data = NULL; + jsestate->escontext.details_wanted = false; + } jsestate->escontext.error_occurred = false; switch (jsexpr->op) @@ -4400,6 +4399,14 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, error = true; } + /* + * When setting up the ErrorSaveContext (if needed) for capturing the + * errors that occur when coercing the JsonBehavior expression, set + * details_wanted to be able to show the actual error message as the + * DETAIL of the error message that tells that it is the JsonBehavior + * expression that caused the error; see ExecEvalJsonCoercionFinish(). + */ + /* Handle ON EMPTY. */ if (empty) { @@ -4410,6 +4417,9 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, if (jsexpr->on_empty->btype != JSON_BEHAVIOR_ERROR) { jsestate->empty.value = BoolGetDatum(true); + /* Set up to catch coercion errors of the ON EMPTY value. */ + jsestate->escontext.error_occurred = false; + jsestate->escontext.details_wanted = true; Assert(jsestate->jump_empty >= 0); return jsestate->jump_empty; } @@ -4417,6 +4427,9 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, else if (jsexpr->on_error->btype != JSON_BEHAVIOR_ERROR) { jsestate->error.value = BoolGetDatum(true); + /* Set up to catch coercion errors of the ON ERROR value. */ + jsestate->escontext.error_occurred = false; + jsestate->escontext.details_wanted = true; Assert(!throw_error && jsestate->jump_error >= 0); return jsestate->jump_error; } @@ -4442,6 +4455,9 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op, *op->resvalue = (Datum) 0; *op->resnull = true; jsestate->error.value = BoolGetDatum(true); + /* Set up to catch coercion errors of the ON ERROR value. */ + jsestate->escontext.error_occurred = false; + jsestate->escontext.details_wanted = true; return jsestate->jump_error; } @@ -4544,9 +4560,33 @@ ExecEvalJsonCoercion(ExprState *state, ExprEvalStep *op, (Node *) escontext); } +static char * +GetJsonBehaviorValueString(JsonBehavior *behavior) +{ + /* + * The order of array elements must correspond to the order of + * JsonBehaviorType members. + */ + const char *behavior_names[] = + { + "NULL", + "ERROR", + "EMPTY", + "TRUE", + "FALSE", + "UNKNOWN", + "EMPTY ARRAY", + "EMPTY OBJECT", + "DEFAULT" + }; + + return pstrdup(behavior_names[behavior->btype]); +} + /* * Checks if an error occurred in ExecEvalJsonCoercion(). If so, this sets - * JsonExprState.error to trigger the ON ERROR handling steps. + * JsonExprState.error to trigger the ON ERROR handling steps, unless the + * error is thrown when coercing a JsonBehavior value. */ void ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op) @@ -4555,8 +4595,28 @@ ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op) if (SOFT_ERROR_OCCURRED(&jsestate->escontext)) { + /* + * jsestate->error or jsetate->empty being set means that the error + * occurred when coercing the JsonBehavior value. Throw the error in + * that case with the actual coercion error message shown in the + * DETAIL part. + */ + if (DatumGetBool(jsestate->error.value)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("could not coerce ON ERROR expression (%s) to the RETURNING type", + GetJsonBehaviorValueString(jsestate->jsexpr->on_error)), + errdetail("%s", jsestate->escontext.error_data->message))); + else if (DatumGetBool(jsestate->empty.value)) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("could not coerce ON EMPTY expression (%s) to the RETURNING type", + GetJsonBehaviorValueString(jsestate->jsexpr->on_empty)), + errdetail("%s", jsestate->escontext.error_data->message))); + *op->resvalue = (Datum) 0; *op->resnull = true; + jsestate->error.value = BoolGetDatum(true); /* @@ -4564,6 +4624,8 @@ ExecEvalJsonCoercionFinish(ExprState *state, ExprEvalStep *op) * JsonBehavior expression. */ jsestate->escontext.error_occurred = false; + jsestate->escontext.error_occurred = false; + jsestate->escontext.details_wanted = true; } } |