v15-0002-delta.patch
application/octet-stream
Filename: v15-0002-delta.patch
Type: application/octet-stream
Part: 0
Message:
Re: SQL/JSON revisited
Patch
Format: unified
Series: patch v15-0002
| File | + | − |
|---|---|---|
| src/backend/executor/execExpr.c | 1 | 1 |
| src/backend/utils/adt/jsonfuncs.c | 63 | 19 |
| src/include/executor/execExpr.h | 2 | 2 |
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;