diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 075c81b558..0dea35a981 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -4559,7 +4559,7 @@ ExecInitJsonItemCoercions(ExprEvalStep *scratch, ExprState *state, scratch->opcode = EEOP_JUMP; /* - * Remember JUMP step address to set the actual jump target addreess + * Remember JUMP step address to set the actual jump target address * below. */ adjust_jumps = lappend_int(adjust_jumps, state->steps_len); diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index dc255354f0..50a3d5d7fa 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -265,7 +265,6 @@ typedef struct PopulateArrayContext int *sizes; /* current dimension counters */ int ndims; /* number of dimensions */ Node *escontext; /* For soft-error capture */ - bool error; /* Caught a soft-error? */ } PopulateArrayContext; /* state for populate_array_json() */ @@ -461,7 +460,8 @@ static void populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims); static void populate_array_check_dimension(PopulateArrayContext *ctx, int ndim); static void populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv); static Datum populate_array(ArrayIOData *aio, const char *colname, - MemoryContext mcxt, JsValue *jsv, Node *escontext); + MemoryContext mcxt, JsValue *jsv, Node *escontext, + bool *isnull); static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname, MemoryContext mcxt, JsValue *jsv, bool isnull); @@ -2520,11 +2520,13 @@ populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim) errhint("See the array element %s.", indices.data))); } - - ctx->error = SOFT_ERROR_OCCURRED(ctx->escontext); } -/* set the number of dimensions of the populated array when it becomes known */ +/* + * Set the number of dimensions of the populated array when it becomes known. + * + * Returns without doing anything if the input (ndims) is erratic. + */ static void populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims) { @@ -2535,7 +2537,8 @@ populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims) if (ndims <= 0) populate_array_report_expected_array(ctx, ndims); - if (ctx->error) + /* Nothing to do on an error. */ + if (SOFT_ERROR_OCCURRED(ctx->escontext)) return; ctx->ndims = ndims; @@ -2561,6 +2564,10 @@ populate_array_check_dimension(PopulateArrayContext *ctx, int ndim) errdetail("Multidimensional arrays must have " "sub-arrays with matching dimensions."))); + /* Nothing to do on an error. */ + if (SOFT_ERROR_OCCURRED(ctx->escontext)) + return; + /* reset the current array dimension size counter */ ctx->sizes[ndim] = 0; @@ -2580,7 +2587,10 @@ populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv) ctx->aio->element_type, ctx->aio->element_typmod, NULL, ctx->mcxt, PointerGetDatum(NULL), - jsv, &element_isnull, NULL); + jsv, &element_isnull, ctx->escontext); + /* Nothing to do on an error. */ + if (SOFT_ERROR_OCCURRED(ctx->escontext)) + return; accumArrayResult(ctx->astate, element, element_isnull, ctx->aio->element_type, ctx->acxt); @@ -2601,6 +2611,10 @@ populate_array_object_start(void *_state) else if (ndim < state->ctx->ndims) populate_array_report_expected_array(state->ctx, ndim); + /* Report that an error occurred. */ + if (SOFT_ERROR_OCCURRED(state->ctx->escontext)) + return JSON_SEM_ACTION_FAILED; + return JSON_SUCCESS; } @@ -2618,6 +2632,10 @@ populate_array_array_end(void *_state) if (ndim < ctx->ndims) populate_array_check_dimension(ctx, ndim); + /* Report that an error occurred. */ + if (SOFT_ERROR_OCCURRED(state->ctx->escontext)) + return JSON_SEM_ACTION_FAILED; + return JSON_SUCCESS; } @@ -2693,6 +2711,10 @@ populate_array_scalar(void *_state, char *token, JsonTokenType tokentype) else if (ndim < ctx->ndims) populate_array_report_expected_array(ctx, ndim); + /* Report that an error occurred. */ + if (SOFT_ERROR_OCCURRED(ctx->escontext)) + return JSON_SEM_ACTION_FAILED; + if (ndim == ctx->ndims) { /* remember the scalar element token */ @@ -2722,7 +2744,13 @@ populate_array_json(PopulateArrayContext *ctx, char *json, int len) sem.array_element_end = populate_array_element_end; sem.scalar = populate_array_scalar; - pg_parse_json_or_errsave(state.lex, &sem, ctx->escontext); + if (!pg_parse_json_or_errsave(state.lex, &sem, ctx->escontext)) + { + /* Nothing to do on an error. */ + Assert(SOFT_ERROR_OCCURRED(ctx->escontext)); + pfree(state.lex); + return; + } /* number of dimensions should be already known */ Assert(ctx->ndims > 0 && ctx->dims); @@ -2750,10 +2778,12 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */ if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc) || JsonContainerIsScalar(jbc)) + { populate_array_report_expected_array(ctx, ndim - 1); - - if (ctx->error) + /* Nothing to do on an error. */ + Assert(SOFT_ERROR_OCCURRED(ctx->escontext)); return; + } it = JsonbIteratorInit(jbc); @@ -2772,7 +2802,12 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */ (tok == WJB_ELEM && (val.type != jbvBinary || !JsonContainerIsArray(val.val.binary.data))))) + { populate_array_assign_ndims(ctx, ndim); + /* Nothing to do on an error. */ + if (SOFT_ERROR_OCCURRED(ctx->escontext)) + return; + } jsv.is_json = false; jsv.val.jsonb = &val; @@ -2790,8 +2825,8 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */ { /* populate child sub-array */ populate_array_dim_jsonb(ctx, &val, ndim + 1); - - if (ctx->error) + /* Nothing to do on an error. */ + if (SOFT_ERROR_OCCURRED(ctx->escontext)) return; /* number of dimensions should be already known */ @@ -2810,13 +2845,18 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */ Assert(tok == WJB_DONE && !it); } -/* recursively populate an array from json/jsonb */ +/* + * Recursively populate an array from json/jsonb + * + * *isnull is set to if an error is reported during parsing. + */ static Datum populate_array(ArrayIOData *aio, const char *colname, MemoryContext mcxt, JsValue *jsv, - Node *escontext) + Node *escontext, + bool *isnull) { PopulateArrayContext ctx; Datum result; @@ -2832,7 +2872,6 @@ populate_array(ArrayIOData *aio, ctx.dims = NULL; ctx.sizes = NULL; ctx.escontext = escontext; - ctx.error = false; if (jsv->is_json) populate_array_json(&ctx, jsv->val.json.str, @@ -2841,13 +2880,17 @@ populate_array(ArrayIOData *aio, else { populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1); - if (!ctx.error) + /* Nothing to do on an error. */ + if (!SOFT_ERROR_OCCURRED(ctx.escontext)) ctx.dims[0] = ctx.sizes[0]; } - /* Caller should check SOFT_ERROR_OCCURRED(escontext)! */ - if (ctx.error) + /* Nothing to return if an error occurred. */ + if (SOFT_ERROR_OCCURRED(ctx.escontext)) + { + *isnull = true; return (Datum) 0; + } Assert(ctx.ndims > 0); @@ -2863,6 +2906,7 @@ populate_array(ArrayIOData *aio, pfree(ctx.sizes); pfree(lbs); + *isnull = false; return result; } @@ -3224,7 +3268,7 @@ populate_record_field(ColumnIOData *col, case TYPECAT_ARRAY: return populate_array(&col->io.array, colname, mcxt, jsv, - escontext); + escontext, isnull); case TYPECAT_COMPOSITE: case TYPECAT_COMPOSITE_DOMAIN: diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 3252bcf1ee..5ebafc18d5 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -903,8 +903,8 @@ typedef struct JsonExprState } input; /* I/O info for output type */ /* - * Either of the following two is used by ExecEvalJsonCoercion() to apply - * coercion to the final result if needed. + * Either of the following two is used by ExecEvalJsonExprCoercion() to + * apply coercion to the final result if needed. */ JsonCoercionState *result_jcstate; JsonItemCoercionsState *item_jcstates;