v17-0002-Add-soft-error-handling-to-populate_record_field.patch
application/octet-stream
Filename: v17-0002-Add-soft-error-handling-to-populate_record_field.patch
Type: application/octet-stream
Part: 1
Message:
Re: remaining sql/json patches
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v17-0002
Subject: Add soft error handling to populate_record_field()
| File | + | − |
|---|---|---|
| contrib/hstore/hstore_io.c | 2 | 1 |
| contrib/hstore/hstore_op.c | 6 | 3 |
| src/backend/catalog/objectaddress.c | 2 | 1 |
| src/backend/executor/execExprInterp.c | 2 | 1 |
| src/backend/utils/adt/arrayfuncs.c | 31 | 12 |
| src/backend/utils/adt/array_userfuncs.c | 3 | 2 |
| src/backend/utils/adt/domains.c | 3 | 2 |
| src/backend/utils/adt/expandedrecord.c | 8 | 4 |
| src/backend/utils/adt/jsonfuncs.c | 217 | 75 |
| src/backend/utils/adt/orderedsetaggs.c | 4 | 2 |
| src/backend/utils/adt/regexp.c | 1 | 1 |
| src/include/utils/array.h | 5 | 2 |
| src/include/utils/builtins.h | 2 | 1 |
| src/pl/plperl/plperl.c | 4 | 3 |
| src/pl/plpgsql/src/pl_exec.c | 3 | 2 |
| src/pl/plpython/plpy_typeio.c | 3 | 2 |
| src/pl/tcl/pltcl.c | 2 | 1 |
| src/test/modules/test_regex/test_regex.c | 4 | 2 |
From ec48283e9f30a7ddf18ca32704e6ec62d139f7a2 Mon Sep 17 00:00:00 2001
From: Amit Langote <amitlan@postgresql.org>
Date: Mon, 11 Sep 2023 21:31:29 +0900
Subject: [PATCH v17 2/5] Add soft error handling to populate_record_field()
An uncoming patch would like the ability to call it from the
executor for some SQL/JSON expression nodes and ask to suppress any
errors that may occur.
This commit does two things mainly:
* It modifies the various interfaces internal to jsonfuncs.c, and in
some cases, some external functions to pass the ErrorSaveContext
around.
* Make necessary modifications to handle the cases where the
processing is aborted partway through various functions that take
an ErrorSaveContext when a soft error occurs.
---
contrib/hstore/hstore_io.c | 3 +-
contrib/hstore/hstore_op.c | 9 +-
src/backend/catalog/objectaddress.c | 3 +-
src/backend/executor/execExprInterp.c | 3 +-
src/backend/utils/adt/array_userfuncs.c | 5 +-
src/backend/utils/adt/arrayfuncs.c | 43 +++-
src/backend/utils/adt/domains.c | 5 +-
src/backend/utils/adt/expandedrecord.c | 12 +-
src/backend/utils/adt/jsonfuncs.c | 292 +++++++++++++++++------
src/backend/utils/adt/orderedsetaggs.c | 6 +-
src/backend/utils/adt/regexp.c | 2 +-
src/include/utils/array.h | 7 +-
src/include/utils/builtins.h | 3 +-
src/pl/plperl/plperl.c | 7 +-
src/pl/plpgsql/src/pl_exec.c | 5 +-
src/pl/plpython/plpy_typeio.c | 5 +-
src/pl/tcl/pltcl.c | 3 +-
src/test/modules/test_regex/test_regex.c | 6 +-
18 files changed, 302 insertions(+), 117 deletions(-)
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index 999ddad76d..fc145faa1b 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -1195,7 +1195,8 @@ hstore_populate_record(PG_FUNCTION_ARGS)
domain_check(HeapTupleGetDatum(rettuple), false,
argtype,
&my_extra->domain_info,
- fcinfo->flinfo->fn_mcxt);
+ fcinfo->flinfo->fn_mcxt,
+ NULL);
ReleaseTupleDesc(tupdesc);
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index 0d4ec16d1e..5d53695be1 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -619,7 +619,8 @@ hstore_slice_to_array(PG_FUNCTION_ARGS)
ARR_NDIM(key_array),
ARR_DIMS(key_array),
ARR_LBOUND(key_array),
- TEXTOID, -1, false, TYPALIGN_INT);
+ TEXTOID, -1, false, TYPALIGN_INT,
+ NULL);
PG_RETURN_POINTER(aout);
}
@@ -762,7 +763,8 @@ hstore_avals(PG_FUNCTION_ARGS)
}
a = construct_md_array(d, nulls, 1, &count, &lb,
- TEXTOID, -1, false, TYPALIGN_INT);
+ TEXTOID, -1, false, TYPALIGN_INT,
+ NULL);
PG_RETURN_POINTER(a);
}
@@ -814,7 +816,8 @@ hstore_to_array_internal(HStore *hs, int ndims)
return construct_md_array(out_datums, out_nulls,
ndims, out_size, lb,
- TEXTOID, -1, false, TYPALIGN_INT);
+ TEXTOID, -1, false, TYPALIGN_INT,
+ NULL);
}
PG_FUNCTION_INFO_V1(hstore_to_array);
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 715201f5a2..e8893613f2 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -6085,7 +6085,8 @@ strlist_to_textarray(List *list)
lb[0] = 1;
arr = construct_md_array(datums, nulls, 1, &j,
- lb, TEXTOID, -1, false, TYPALIGN_INT);
+ lb, TEXTOID, -1, false, TYPALIGN_INT,
+ NULL);
MemoryContextDelete(memcxt);
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 86dff69f4d..7b3e1d071d 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2742,7 +2742,8 @@ ExecEvalArrayExpr(ExprState *state, ExprEvalStep *op)
element_type,
op->d.arrayexpr.elemlength,
op->d.arrayexpr.elembyval,
- op->d.arrayexpr.elemalign);
+ op->d.arrayexpr.elemalign,
+ NULL);
}
else
{
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 5c4fdcfba4..801c5efd87 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -857,7 +857,7 @@ array_agg_finalfn(PG_FUNCTION_ARGS)
*/
result = makeMdArrayResult(state, 1, dims, lbs,
CurrentMemoryContext,
- false);
+ false, NULL);
PG_RETURN_DATUM(result);
}
@@ -1622,7 +1622,8 @@ array_shuffle_n(ArrayType *array, int n, bool keep_lb,
rlbs[0] = 1;
result = construct_md_array(elms, nuls, ndim, rdims, rlbs,
- elmtyp, elmlen, elmbyval, elmalign);
+ elmtyp, elmlen, elmbyval, elmalign,
+ NULL);
pfree(elms);
pfree(nuls);
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 7828a6264b..02bc483ff6 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -21,6 +21,7 @@
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
+#include "nodes/miscnodes.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/optimizer.h"
@@ -2321,7 +2322,8 @@ array_set_element(Datum arraydatum,
return PointerGetDatum(construct_md_array(&dataValue, &isNull,
nSubscripts, dim, lb,
elmtype,
- elmlen, elmbyval, elmalign));
+ elmlen, elmbyval, elmalign,
+ NULL));
}
if (ndim != nSubscripts)
@@ -2881,7 +2883,8 @@ array_set_slice(Datum arraydatum,
return PointerGetDatum(construct_md_array(dvalues, dnulls, nSubscripts,
dim, lb, elmtype,
- elmlen, elmbyval, elmalign));
+ elmlen, elmbyval, elmalign,
+ NULL));
}
if (ndim < nSubscripts || ndim <= 0 || ndim > MAXDIM)
@@ -3328,7 +3331,8 @@ construct_array(Datum *elems, int nelems,
lbs[0] = 1;
return construct_md_array(elems, NULL, 1, dims, lbs,
- elmtype, elmlen, elmbyval, elmalign);
+ elmtype, elmlen, elmbyval, elmalign,
+ NULL);
}
/*
@@ -3432,6 +3436,8 @@ construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
* elem values will be copied into the object even if pass-by-ref type.
* Also note the result will be 0-D not ndims-D if any dims[i] = 0.
*
+ * NULL is returned if an error occurs and escontext is valid.
+ *
* NOTE: it would be cleaner to look up the elmlen/elmbval/elmalign info
* from the system catalogs, given the elmtype. However, the caller is
* in a better position to cache this info across multiple uses, or even
@@ -3443,7 +3449,8 @@ construct_md_array(Datum *elems,
int ndims,
int *dims,
int *lbs,
- Oid elmtype, int elmlen, bool elmbyval, char elmalign)
+ Oid elmtype, int elmlen, bool elmbyval, char elmalign,
+ Node *escontext)
{
ArrayType *result;
bool hasnulls;
@@ -3453,15 +3460,18 @@ construct_md_array(Datum *elems,
int nelems;
if (ndims < 0) /* we do allow zero-dimension arrays */
- ereport(ERROR,
+ errsave(escontext,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid number of dimensions: %d", ndims)));
if (ndims > MAXDIM)
- ereport(ERROR,
+ errsave(escontext,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
ndims, MAXDIM)));
+ if (SOFT_ERROR_OCCURRED(escontext))
+ return NULL;
+
/* This checks for overflow of the array dimensions */
nelems = ArrayGetNItems(ndims, dims);
ArrayCheckBounds(ndims, dims, lbs);
@@ -3485,7 +3495,13 @@ construct_md_array(Datum *elems,
elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i]));
nbytes = att_addlength_datum(nbytes, elmlen, elems[i]);
nbytes = att_align_nominal(nbytes, elmalign);
- /* check for overflow of total request */
+ /*
+ * check for overflow of total request
+ *
+ * The following should be perhaps be errsave() to respect caller's
+ * wish to suppress the error, but it also doesn't seem like a good
+ * idea to ignore the problem being reported here.
+ */
if (!AllocSizeIsValid(nbytes))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
@@ -4690,7 +4706,8 @@ array_iterate(ArrayIterator iterator, Datum *value, bool *isnull)
ARR_ELEMTYPE(iterator->arr),
iterator->typlen,
iterator->typbyval,
- iterator->typalign);
+ iterator->typalign,
+ NULL);
*isnull = false;
*value = PointerGetDatum(result);
@@ -5377,7 +5394,7 @@ makeArrayResult(ArrayBuildState *astate,
lbs[0] = 1;
return makeMdArrayResult(astate, ndims, dims, lbs, rcontext,
- astate->private_cxt);
+ astate->private_cxt, NULL);
}
/*
@@ -5401,7 +5418,8 @@ makeMdArrayResult(ArrayBuildState *astate,
int *dims,
int *lbs,
MemoryContext rcontext,
- bool release)
+ bool release,
+ Node *escontext)
{
ArrayType *result;
MemoryContext oldcontext;
@@ -5417,7 +5435,8 @@ makeMdArrayResult(ArrayBuildState *astate,
astate->element_type,
astate->typlen,
astate->typbyval,
- astate->typalign);
+ astate->typalign,
+ NULL);
MemoryContextSwitchTo(oldcontext);
@@ -5817,7 +5836,7 @@ makeArrayResultAny(ArrayBuildStateAny *astate,
lbs[0] = 1;
result = makeMdArrayResult(astate->scalarstate, ndims, dims, lbs,
- rcontext, release);
+ rcontext, release, NULL);
}
else
{
diff --git a/src/backend/utils/adt/domains.c b/src/backend/utils/adt/domains.c
index 8d766f68e3..f8669ee1b5 100644
--- a/src/backend/utils/adt/domains.c
+++ b/src/backend/utils/adt/domains.c
@@ -341,7 +341,8 @@ domain_recv(PG_FUNCTION_ARGS)
*/
void
domain_check(Datum value, bool isnull, Oid domainType,
- void **extra, MemoryContext mcxt)
+ void **extra, MemoryContext mcxt,
+ Node *escontext)
{
DomainIOData *my_extra = NULL;
@@ -365,7 +366,7 @@ domain_check(Datum value, bool isnull, Oid domainType,
/*
* Do the necessary checks to ensure it's a valid domain value.
*/
- domain_check_input(value, isnull, my_extra, NULL);
+ domain_check_input(value, isnull, my_extra, escontext);
}
/*
diff --git a/src/backend/utils/adt/expandedrecord.c b/src/backend/utils/adt/expandedrecord.c
index c46e5aa36f..358ee015a5 100644
--- a/src/backend/utils/adt/expandedrecord.c
+++ b/src/backend/utils/adt/expandedrecord.c
@@ -1359,7 +1359,8 @@ expanded_record_set_fields(ExpandedRecordHeader *erh,
domain_check(ExpandedRecordGetRODatum(erh), false,
erh->er_decltypeid,
&erh->er_domaininfo,
- erh->hdr.eoh_context);
+ erh->hdr.eoh_context,
+ NULL);
}
MemoryContextSwitchTo(oldcxt);
@@ -1561,7 +1562,8 @@ check_domain_for_new_field(ExpandedRecordHeader *erh, int fnumber,
domain_check(ExpandedRecordGetRODatum(dummy_erh), false,
erh->er_decltypeid,
&erh->er_domaininfo,
- erh->hdr.eoh_context);
+ erh->hdr.eoh_context,
+ NULL);
MemoryContextSwitchTo(oldcxt);
@@ -1587,7 +1589,8 @@ check_domain_for_new_tuple(ExpandedRecordHeader *erh, HeapTuple tuple)
domain_check((Datum) 0, true,
erh->er_decltypeid,
&erh->er_domaininfo,
- erh->hdr.eoh_context);
+ erh->hdr.eoh_context,
+ NULL);
MemoryContextSwitchTo(oldcxt);
@@ -1624,7 +1627,8 @@ check_domain_for_new_tuple(ExpandedRecordHeader *erh, HeapTuple tuple)
domain_check(ExpandedRecordGetRODatum(dummy_erh), false,
erh->er_decltypeid,
&erh->er_domaininfo,
- erh->hdr.eoh_context);
+ erh->hdr.eoh_context,
+ NULL);
MemoryContextSwitchTo(oldcxt);
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index a4bfa5e404..cb9df6caf2 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -265,6 +265,7 @@ typedef struct PopulateArrayContext
int *dims; /* dimensions */
int *sizes; /* current dimension counters */
int ndims; /* number of dimensions */
+ Node *escontext; /* For soft-error handling */
} PopulateArrayContext;
/* state for populate_array_json() */
@@ -389,7 +390,8 @@ static JsonParseErrorType elements_array_element_end(void *state, bool isnull);
static JsonParseErrorType elements_scalar(void *state, char *token, JsonTokenType tokentype);
/* turn a json object into a hash table */
-static HTAB *get_json_object_as_hash(char *json, int len, const char *funcname);
+static HTAB *get_json_object_as_hash(char *json, int len, const char *funcname,
+ Node *escontext);
/* semantic actions for populate_array_json */
static JsonParseErrorType populate_array_object_start(void *_state);
@@ -431,37 +433,42 @@ static Datum populate_record_worker(FunctionCallInfo fcinfo, const char *funcnam
/* helper functions for populate_record[set] */
static HeapTupleHeader populate_record(TupleDesc tupdesc, RecordIOData **record_p,
HeapTupleHeader defaultval, MemoryContext mcxt,
- JsObject *obj);
+ JsObject *obj, Node *escontext);
static void get_record_type_from_argument(FunctionCallInfo fcinfo,
const char *funcname,
PopulateRecordCache *cache);
static void get_record_type_from_query(FunctionCallInfo fcinfo,
const char *funcname,
PopulateRecordCache *cache);
-static void JsValueToJsObject(JsValue *jsv, JsObject *jso);
+static bool JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext);
static Datum populate_composite(CompositeIOData *io, Oid typid,
const char *colname, MemoryContext mcxt,
- HeapTupleHeader defaultval, JsValue *jsv, bool isnull);
-static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv);
+ HeapTupleHeader defaultval, JsValue *jsv, bool *isnull,
+ Node *escontext);
+static Datum populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv,
+ bool *isnull, Node *escontext);
static void prepare_column_cache(ColumnIOData *column, Oid typid, int32 typmod,
MemoryContext mcxt, bool need_scalar);
static Datum populate_record_field(ColumnIOData *col, Oid typid, int32 typmod,
const char *colname, MemoryContext mcxt, Datum defaultval,
- JsValue *jsv, bool *isnull);
+ JsValue *jsv, bool *isnull, Node *escontext);
static RecordIOData *allocate_record_info(MemoryContext mcxt, int ncolumns);
static bool JsObjectGetField(JsObject *obj, char *field, JsValue *jsv);
static void populate_recordset_record(PopulateRecordsetState *state, JsObject *obj);
-static void populate_array_json(PopulateArrayContext *ctx, char *json, int len);
-static void populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv,
+static bool populate_array_json(PopulateArrayContext *ctx, char *json, int len);
+static bool populate_array_dim_jsonb(PopulateArrayContext *ctx, JsonbValue *jbv,
int ndim);
static void populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim);
-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 bool populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims);
+static bool populate_array_check_dimension(PopulateArrayContext *ctx, int ndim);
+static bool populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv);
static Datum populate_array(ArrayIOData *aio, const char *colname,
- MemoryContext mcxt, JsValue *jsv);
+ MemoryContext mcxt, JsValue *jsv,
+ bool *isnull,
+ Node *escontext);
static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname,
- MemoryContext mcxt, JsValue *jsv, bool isnull);
+ MemoryContext mcxt, JsValue *jsv, bool isnull,
+ Node *escontext);
/* functions supporting jsonb_delete, jsonb_set and jsonb_concat */
static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
@@ -2477,19 +2484,23 @@ json_to_record(PG_FUNCTION_ARGS)
true, false);
}
-/* helper function for diagnostics */
+/*
+ * Helper function for diagnostics
+ *
+ * Returns false if the input is erratic.
+ */
static void
populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
{
if (ndim <= 0)
{
if (ctx->colname)
- ereport(ERROR,
+ errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"),
errhint("See the value of key \"%s\".", ctx->colname)));
else
- ereport(ERROR,
+ errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array")));
}
@@ -2506,13 +2517,13 @@ populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
appendStringInfo(&indices, "[%d]", ctx->sizes[i]);
if (ctx->colname)
- ereport(ERROR,
+ errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"),
errhint("See the array element %s of key \"%s\".",
indices.data, ctx->colname)));
else
- ereport(ERROR,
+ errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected JSON array"),
errhint("See the array element %s.",
@@ -2520,8 +2531,12 @@ populate_array_report_expected_array(PopulateArrayContext *ctx, int ndim)
}
}
-/* set the number of dimensions of the populated array when it becomes known */
-static void
+/*
+ * Set the number of dimensions of the populated array when it becomes known.
+ *
+ * Returns false if the input (ndims) is erratic.
+ */
+static bool
populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
{
int i;
@@ -2529,7 +2544,12 @@ populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
Assert(ctx->ndims <= 0);
if (ndims <= 0)
+ {
populate_array_report_expected_array(ctx, ndims);
+ /* Getting here means the error was reported softly. */
+ Assert(SOFT_ERROR_OCCURRED(ctx->escontext));
+ return false;
+ }
ctx->ndims = ndims;
ctx->dims = palloc(sizeof(int) * ndims);
@@ -2537,10 +2557,16 @@ populate_array_assign_ndims(PopulateArrayContext *ctx, int ndims)
for (i = 0; i < ndims; i++)
ctx->dims[i] = -1; /* dimensions are unknown yet */
+
+ return true;
}
-/* check the populated subarray dimension */
-static void
+/*
+ * Check the populated subarray dimension
+ *
+ * Returns false if the input (ndims) is erratic.
+ */
+static bool
populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
{
int dim = ctx->sizes[ndim]; /* current dimension counter */
@@ -2548,21 +2574,31 @@ populate_array_check_dimension(PopulateArrayContext *ctx, int ndim)
if (ctx->dims[ndim] == -1)
ctx->dims[ndim] = dim; /* assign dimension if not yet known */
else if (ctx->dims[ndim] != dim)
- ereport(ERROR,
+ errsave(ctx->escontext,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("malformed JSON array"),
errdetail("Multidimensional arrays must have "
"sub-arrays with matching dimensions.")));
+ /* Nothing to do on an error. */
+ if (SOFT_ERROR_OCCURRED(ctx->escontext))
+ return false;
+
/* reset the current array dimension size counter */
ctx->sizes[ndim] = 0;
/* increment the parent dimension counter if it is a nested sub-array */
if (ndim > 0)
ctx->sizes[ndim - 1]++;
+
+ return true;
}
-static void
+/*
+ * Returns true if the array element value was successfully extracted from jsv
+ * and added to ctx->astate. False if an error occurred when doing so.
+ */
+static bool
populate_array_element(PopulateArrayContext *ctx, int ndim, JsValue *jsv)
{
Datum element;
@@ -2573,13 +2609,18 @@ 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);
+ jsv, &element_isnull, ctx->escontext);
+ /* Nothing to do on an error. */
+ if (SOFT_ERROR_OCCURRED(ctx->escontext))
+ return false;
accumArrayResult(ctx->astate, element, element_isnull,
ctx->aio->element_type, ctx->acxt);
Assert(ndim > 0);
ctx->sizes[ndim - 1]++; /* increment current dimension counter */
+
+ return true;
}
/* json object start handler for populate_array_json() */
@@ -2594,6 +2635,10 @@ populate_array_object_start(void *_state)
else if (ndim < state->ctx->ndims)
populate_array_report_expected_array(state->ctx, ndim);
+ /* Report if an error occurred. */
+ if (SOFT_ERROR_OCCURRED(state->ctx->escontext))
+ return JSON_SEM_ACTION_FAILED;
+
return JSON_SUCCESS;
}
@@ -2609,7 +2654,11 @@ populate_array_array_end(void *_state)
populate_array_assign_ndims(ctx, ndim + 1);
if (ndim < ctx->ndims)
- populate_array_check_dimension(ctx, ndim);
+ {
+ /* Report if an error occurred. */
+ if (!populate_array_check_dimension(ctx, ndim))
+ return JSON_SEM_ACTION_FAILED;
+ }
return JSON_SUCCESS;
}
@@ -2667,7 +2716,8 @@ populate_array_element_end(void *_state, bool isnull)
state->element_start) * sizeof(char);
}
- populate_array_element(ctx, ndim, &jsv);
+ if (!populate_array_element(ctx, ndim, &jsv))
+ return JSON_SEM_ACTION_FAILED;
}
return JSON_SUCCESS;
@@ -2686,6 +2736,10 @@ populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
else if (ndim < ctx->ndims)
populate_array_report_expected_array(ctx, ndim);
+ /* Report if an error occurred. */
+ if (SOFT_ERROR_OCCURRED(ctx->escontext))
+ return JSON_SEM_ACTION_FAILED;
+
if (ndim == ctx->ndims)
{
/* remember the scalar element token */
@@ -2697,8 +2751,12 @@ populate_array_scalar(void *_state, char *token, JsonTokenType tokentype)
return JSON_SUCCESS;
}
-/* parse a json array and populate array */
-static void
+/*
+ * Parse a json array and populate array
+ *
+ * Returns false if an error occurs when parsing.
+ */
+static bool
populate_array_json(PopulateArrayContext *ctx, char *json, int len)
{
PopulateArrayState state;
@@ -2715,19 +2773,25 @@ 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_ereport(state.lex, &sem);
-
- /* number of dimensions should be already known */
- Assert(ctx->ndims > 0 && ctx->dims);
+ if (pg_parse_json_or_errsave(state.lex, &sem, ctx->escontext))
+ {
+ /* number of dimensions should be already known */
+ Assert(ctx->ndims > 0 && ctx->dims);
+ }
pfree(state.lex);
+
+ return !SOFT_ERROR_OCCURRED(ctx->escontext);
}
/*
* populate_array_dim_jsonb() -- Iterate recursively through jsonb sub-array
* elements and accumulate result using given ArrayBuildState.
+ *
+ * Returns false if we return partway through because of an error in a
+ * subroutine.
*/
-static void
+static bool
populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
JsonbValue *jbv, /* jsonb sub-array */
int ndim) /* current dimension */
@@ -2741,7 +2805,12 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
check_stack_depth();
if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc))
+ {
populate_array_report_expected_array(ctx, ndim - 1);
+ /* Getting here means the error was reported softly. */
+ Assert(SOFT_ERROR_OCCURRED(ctx->escontext));
+ return false;
+ }
Assert(!JsonContainerIsScalar(jbc));
@@ -2762,7 +2831,10 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
(tok == WJB_ELEM &&
(val.type != jbvBinary ||
!JsonContainerIsArray(val.val.binary.data)))))
- populate_array_assign_ndims(ctx, ndim);
+ {
+ if (!populate_array_assign_ndims(ctx, ndim))
+ return false;
+ }
jsv.is_json = false;
jsv.val.jsonb = &val;
@@ -2775,16 +2847,21 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
* it is not the innermost dimension.
*/
if (ctx->ndims > 0 && ndim >= ctx->ndims)
- populate_array_element(ctx, ndim, &jsv);
+ {
+ if (!populate_array_element(ctx, ndim, &jsv))
+ return false;
+ }
else
{
- /* populate child sub-array */
- populate_array_dim_jsonb(ctx, &val, ndim + 1);
+ /* populate child sub-array; nothing to do on an error. */
+ if (!populate_array_dim_jsonb(ctx, &val, ndim + 1))
+ return false;
/* number of dimensions should be already known */
Assert(ctx->ndims > 0 && ctx->dims);
- populate_array_check_dimension(ctx, ndim);
+ if (!populate_array_check_dimension(ctx, ndim))
+ return false;
}
tok = JsonbIteratorNext(&it, &val, true);
@@ -2795,14 +2872,22 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
/* free iterator, iterating until WJB_DONE */
tok = JsonbIteratorNext(&it, &val, true);
Assert(tok == WJB_DONE && !it);
+
+ return true;
}
-/* recursively populate an array from json/jsonb */
+/*
+ * Recursively populate an array from json/jsonb
+ *
+ * *isnull is set to true if an error is reported during parsing.
+ */
static Datum
populate_array(ArrayIOData *aio,
const char *colname,
MemoryContext mcxt,
- JsValue *jsv)
+ JsValue *jsv,
+ bool *isnull,
+ Node *escontext)
{
PopulateArrayContext ctx;
Datum result;
@@ -2817,14 +2902,26 @@ populate_array(ArrayIOData *aio,
ctx.ndims = 0; /* unknown yet */
ctx.dims = NULL;
ctx.sizes = NULL;
+ ctx.escontext = escontext;
if (jsv->is_json)
- populate_array_json(&ctx, jsv->val.json.str,
- jsv->val.json.len >= 0 ? jsv->val.json.len
- : strlen(jsv->val.json.str));
+ {
+ if (!populate_array_json(&ctx, jsv->val.json.str,
+ jsv->val.json.len >= 0 ? jsv->val.json.len
+ : strlen(jsv->val.json.str)))
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
+ }
else
{
- populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1);
+ /* Nothing to do on an error. */
+ if (!populate_array_dim_jsonb(&ctx, jsv->val.jsonb, 1))
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
ctx.dims[0] = ctx.sizes[0];
}
@@ -2836,17 +2933,22 @@ populate_array(ArrayIOData *aio,
lbs[i] = 1;
result = makeMdArrayResult(ctx.astate, ctx.ndims, ctx.dims, lbs,
- ctx.acxt, true);
+ ctx.acxt, true, escontext);
pfree(ctx.dims);
pfree(ctx.sizes);
pfree(lbs);
+ *isnull = false;
return result;
}
-static void
-JsValueToJsObject(JsValue *jsv, JsObject *jso)
+/*
+ * Returns false if an error occurs, provided escontext points to an
+ * ErrorSaveContext.
+ */
+static bool
+JsValueToJsObject(JsValue *jsv, JsObject *jso, Node *escontext)
{
jso->is_json = jsv->is_json;
@@ -2858,7 +2960,8 @@ JsValueToJsObject(JsValue *jsv, JsObject *jso)
jsv->val.json.len >= 0
? jsv->val.json.len
: strlen(jsv->val.json.str),
- "populate_composite");
+ "populate_composite",
+ escontext);
}
else
{
@@ -2876,7 +2979,7 @@ JsValueToJsObject(JsValue *jsv, JsObject *jso)
is_scalar = IsAJsonbScalar(jbv) ||
(jbv->type == jbvBinary &&
JsonContainerIsScalar(jbv->val.binary.data));
- ereport(ERROR,
+ errsave(escontext,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
is_scalar
? errmsg("cannot call %s on a scalar",
@@ -2885,6 +2988,8 @@ JsValueToJsObject(JsValue *jsv, JsObject *jso)
"populate_composite")));
}
}
+
+ return !SOFT_ERROR_OCCURRED(escontext);
}
/* acquire or update cached tuple descriptor for a composite type */
@@ -2911,7 +3016,12 @@ update_cached_tupdesc(CompositeIOData *io, MemoryContext mcxt)
}
}
-/* recursively populate a composite (row type) value from json/jsonb */
+/*
+ * Recursively populate a composite (row type) value from json/jsonb
+ *
+ * Returns null if an error occurs in a subroutine, provided escontext points
+ * to an ErrorSaveContext.
+ */
static Datum
populate_composite(CompositeIOData *io,
Oid typid,
@@ -2919,14 +3029,15 @@ populate_composite(CompositeIOData *io,
MemoryContext mcxt,
HeapTupleHeader defaultval,
JsValue *jsv,
- bool isnull)
+ bool *isnull,
+ Node *escontext)
{
Datum result;
/* acquire/update cached tuple descriptor */
update_cached_tupdesc(io, mcxt);
- if (isnull)
+ if (*isnull)
result = (Datum) 0;
else
{
@@ -2934,11 +3045,15 @@ populate_composite(CompositeIOData *io,
JsObject jso;
/* prepare input value */
- JsValueToJsObject(jsv, &jso);
+ if (!JsValueToJsObject(jsv, &jso, escontext))
+ {
+ *isnull = true;
+ return (Datum) 0;
+ }
/* populate resulting record tuple */
tuple = populate_record(io->tupdesc, &io->record_io,
- defaultval, mcxt, &jso);
+ defaultval, mcxt, &jso, escontext);
result = HeapTupleHeaderGetDatum(tuple);
JsObjectFree(&jso);
@@ -2950,14 +3065,20 @@ populate_composite(CompositeIOData *io,
* now, we can tell by comparing typid to base_typid.)
*/
if (typid != io->base_typid && typid != RECORDOID)
- domain_check(result, isnull, typid, &io->domain_info, mcxt);
+ domain_check(result, *isnull, typid, &io->domain_info, mcxt, escontext);
return result;
}
-/* populate non-null scalar value from json/jsonb value */
+/*
+ * Populate non-null scalar value from json/jsonb value.
+ *
+ * Returns null if an error occurs during the call to type input function,
+ * provided escontext is valid.
+ */
static Datum
-populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv)
+populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv,
+ bool *isnull, Node *escontext)
{
Datum res;
char *str = NULL;
@@ -3028,7 +3149,12 @@ populate_scalar(ScalarIOData *io, Oid typid, int32 typmod, JsValue *jsv)
elog(ERROR, "unrecognized jsonb type: %d", (int) jbv->type);
}
- res = InputFunctionCall(&io->typiofunc, str, io->typioparam, typmod);
+ if (!InputFunctionCallSafe(&io->typiofunc, str, io->typioparam, typmod,
+ escontext, &res))
+ {
+ res = (Datum) 0;
+ *isnull = true;
+ }
/* free temporary buffer */
if (str != json)
@@ -3043,7 +3169,8 @@ populate_domain(DomainIOData *io,
const char *colname,
MemoryContext mcxt,
JsValue *jsv,
- bool isnull)
+ bool isnull,
+ Node *escontext)
{
Datum res;
@@ -3054,11 +3181,11 @@ populate_domain(DomainIOData *io,
res = populate_record_field(io->base_io,
io->base_typid, io->base_typmod,
colname, mcxt, PointerGetDatum(NULL),
- jsv, &isnull);
- Assert(!isnull);
+ jsv, &isnull, escontext);
+ Assert(!isnull || SOFT_ERROR_OCCURRED(escontext));
}
- domain_check(res, isnull, typid, &io->domain_info, mcxt);
+ domain_check(res, isnull, typid, &io->domain_info, mcxt, escontext);
return res;
}
@@ -3159,7 +3286,8 @@ populate_record_field(ColumnIOData *col,
MemoryContext mcxt,
Datum defaultval,
JsValue *jsv,
- bool *isnull)
+ bool *isnull,
+ Node *escontext)
{
TypeCat typcat;
@@ -3192,10 +3320,12 @@ populate_record_field(ColumnIOData *col,
switch (typcat)
{
case TYPECAT_SCALAR:
- return populate_scalar(&col->scalar_io, typid, typmod, jsv);
+ return populate_scalar(&col->scalar_io, typid, typmod, jsv,
+ isnull, escontext);
case TYPECAT_ARRAY:
- return populate_array(&col->io.array, colname, mcxt, jsv);
+ return populate_array(&col->io.array, colname, mcxt, jsv,
+ isnull, escontext);
case TYPECAT_COMPOSITE:
case TYPECAT_COMPOSITE_DOMAIN:
@@ -3204,11 +3334,12 @@ populate_record_field(ColumnIOData *col,
DatumGetPointer(defaultval)
? DatumGetHeapTupleHeader(defaultval)
: NULL,
- jsv, *isnull);
+ jsv, isnull,
+ escontext);
case TYPECAT_DOMAIN:
return populate_domain(&col->io.domain, typid, colname, mcxt,
- jsv, *isnull);
+ jsv, *isnull, escontext);
default:
elog(ERROR, "unrecognized type category '%c'", typcat);
@@ -3265,7 +3396,8 @@ populate_record(TupleDesc tupdesc,
RecordIOData **record_p,
HeapTupleHeader defaultval,
MemoryContext mcxt,
- JsObject *obj)
+ JsObject *obj,
+ Node *escontext)
{
RecordIOData *record = *record_p;
Datum *values;
@@ -3357,7 +3489,8 @@ populate_record(TupleDesc tupdesc,
mcxt,
nulls[i] ? (Datum) 0 : values[i],
&field,
- &nulls[i]);
+ &nulls[i],
+ escontext);
}
res = heap_form_tuple(tupdesc, values, nulls);
@@ -3444,6 +3577,7 @@ populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
JsValue jsv = {0};
HeapTupleHeader rec;
Datum rettuple;
+ bool isnull;
JsonbValue jbv;
MemoryContext fnmcxt = fcinfo->flinfo->fn_mcxt;
PopulateRecordCache *cache = fcinfo->flinfo->fn_extra;
@@ -3530,8 +3664,11 @@ populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
jbv.val.binary.len = VARSIZE(jb) - VARHDRSZ;
}
+ isnull = false;
rettuple = populate_composite(&cache->c.io.composite, cache->argtype,
- NULL, fnmcxt, rec, &jsv, false);
+ NULL, fnmcxt, rec, &jsv, &isnull,
+ NULL);
+ Assert(!isnull);
PG_RETURN_DATUM(rettuple);
}
@@ -3540,9 +3677,13 @@ populate_record_worker(FunctionCallInfo fcinfo, const char *funcname,
* get_json_object_as_hash
*
* decompose a json object into a hash table.
+ *
+ * Returns false if we return partway through because of an error
+ * in pg_parse_json_or_errsave() below.
*/
static HTAB *
-get_json_object_as_hash(char *json, int len, const char *funcname)
+get_json_object_as_hash(char *json, int len, const char *funcname,
+ Node *escontext)
{
HASHCTL ctl;
HTAB *tab;
@@ -3571,7 +3712,7 @@ get_json_object_as_hash(char *json, int len, const char *funcname)
sem->object_field_start = hash_object_field_start;
sem->object_field_end = hash_object_field_end;
- pg_parse_json_or_ereport(lex, sem);
+ pg_parse_json_or_errsave(lex, sem, escontext);
return tab;
}
@@ -3740,14 +3881,15 @@ populate_recordset_record(PopulateRecordsetState *state, JsObject *obj)
&cache->c.io.composite.record_io,
state->rec,
cache->fn_mcxt,
- obj);
+ obj,
+ NULL);
/* if it's domain over composite, check domain constraints */
if (cache->c.typcat == TYPECAT_COMPOSITE_DOMAIN)
domain_check(HeapTupleHeaderGetDatum(tuphead), false,
cache->argtype,
&cache->c.io.composite.domain_info,
- cache->fn_mcxt);
+ cache->fn_mcxt, NULL);
/* ok, save into tuplestore */
tuple.t_len = HeapTupleHeaderGetDatumLength(tuphead);
diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c
index 2582a5cf45..d90ec30a02 100644
--- a/src/backend/utils/adt/orderedsetaggs.c
+++ b/src/backend/utils/adt/orderedsetaggs.c
@@ -840,7 +840,8 @@ percentile_disc_multi_final(PG_FUNCTION_ARGS)
osastate->qstate->sortColType,
osastate->qstate->typLen,
osastate->qstate->typByVal,
- osastate->qstate->typAlign));
+ osastate->qstate->typAlign,
+ NULL));
}
/*
@@ -996,7 +997,8 @@ percentile_cont_multi_final_common(FunctionCallInfo fcinfo,
expect_type,
typLen,
typByVal,
- typAlign));
+ typAlign,
+ NULL));
}
/*
diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c
index 702cd52b6d..e507f43c8d 100644
--- a/src/backend/utils/adt/regexp.c
+++ b/src/backend/utils/adt/regexp.c
@@ -1665,7 +1665,7 @@ build_regexp_match_result(regexp_matches_ctx *matchctx)
lbs[0] = 1;
/* XXX: this hardcodes assumptions about the text type */
return construct_md_array(elems, nulls, 1, dims, lbs,
- TEXTOID, -1, false, TYPALIGN_INT);
+ TEXTOID, -1, false, TYPALIGN_INT, NULL);
}
/*
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index b13dfb345e..c1abecd3fc 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -62,6 +62,7 @@
#define ARRAY_H
#include "fmgr.h"
+#include "nodes/nodes.h"
#include "utils/expandeddatum.h"
/* avoid including execnodes.h here */
@@ -393,7 +394,8 @@ extern ArrayType *construct_md_array(Datum *elems,
int ndims,
int *dims,
int *lbs,
- Oid elmtype, int elmlen, bool elmbyval, char elmalign);
+ Oid elmtype, int elmlen, bool elmbyval, char elmalign,
+ Node *escontext);
extern ArrayType *construct_empty_array(Oid elmtype);
extern ExpandedArrayHeader *construct_empty_expanded_array(Oid element_type,
MemoryContext parentcontext,
@@ -419,7 +421,8 @@ extern ArrayBuildState *accumArrayResult(ArrayBuildState *astate,
extern Datum makeArrayResult(ArrayBuildState *astate,
MemoryContext rcontext);
extern Datum makeMdArrayResult(ArrayBuildState *astate, int ndims,
- int *dims, int *lbs, MemoryContext rcontext, bool release);
+ int *dims, int *lbs, MemoryContext rcontext, bool release,
+ Node *escontext);
extern ArrayBuildStateArr *initArrayResultArr(Oid array_type, Oid element_type,
MemoryContext rcontext, bool subcontext);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 2f8b46d6da..4e1e655652 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -27,7 +27,8 @@ extern bool parse_bool_with_len(const char *value, size_t len, bool *result);
/* domains.c */
extern void domain_check(Datum value, bool isnull, Oid domainType,
- void **extra, MemoryContext mcxt);
+ void **extra, MemoryContext mcxt,
+ Node *escontext);
extern int errdatatype(Oid datatypeOid);
extern int errdomainconstraint(Oid datatypeOid, const char *conname);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 863864253f..5410a37068 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1292,7 +1292,7 @@ plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
lbs[i] = 1;
return makeMdArrayResult(astate, ndims, dims, lbs,
- CurrentMemoryContext, true);
+ CurrentMemoryContext, true, NULL);
}
/* Get the information needed to convert data to the specified PG type */
@@ -1403,7 +1403,7 @@ plperl_sv_to_datum(SV *sv, Oid typid, int32 typmod,
ret = plperl_hash_to_datum(sv, td);
if (isdomain)
- domain_check(ret, false, typid, NULL, NULL);
+ domain_check(ret, false, typid, NULL, NULL, NULL);
/* Release on the result of get_call_result_type is harmless */
ReleaseTupleDesc(td);
@@ -3373,7 +3373,8 @@ plperl_return_next_internal(SV *sv)
domain_check(HeapTupleGetDatum(tuple), false,
current_call_data->cdomain_oid,
¤t_call_data->cdomain_info,
- rsi->econtext->ecxt_per_query_memory);
+ rsi->econtext->ecxt_per_query_memory,
+ NULL);
tuplestore_puttuple(current_call_data->tuple_store, tuple);
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 4b76f7699a..0c5d5263c5 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -713,7 +713,7 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
/* and check domain constraints */
/* XXX allowing caching here would be good, too */
domain_check(estate.retval, false, resultTypeId,
- NULL, NULL);
+ NULL, NULL, NULL);
break;
case TYPEFUNC_RECORD:
@@ -1494,7 +1494,8 @@ plpgsql_fulfill_promise(PLpgSQL_execstate *estate,
PointerGetDatum(construct_md_array(elems, NULL,
1, dims, lbs,
TEXTOID,
- -1, false, TYPALIGN_INT)),
+ -1, false, TYPALIGN_INT,
+ NULL)),
false, true);
}
else
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index db14c5f8da..886118ce01 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -1104,7 +1104,8 @@ PLyObject_ToDomain(PLyObToDatum *arg, PyObject *plrv,
result = base->func(base, plrv, isnull, inarray);
domain_check(result, *isnull, arg->typoid,
- &arg->u.domain.domain_info, arg->mcxt);
+ &arg->u.domain.domain_info, arg->mcxt,
+ NULL);
return result;
}
@@ -1177,7 +1178,7 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv,
lbs[i] = 1;
return makeMdArrayResult(astate, ndims, dims, lbs,
- CurrentMemoryContext, true);
+ CurrentMemoryContext, true, NULL);
}
/*
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index e8f9d7b289..a7adb42ff0 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -3240,7 +3240,8 @@ pltcl_build_tuple_result(Tcl_Interp *interp, Tcl_Obj **kvObjv, int kvObjc,
domain_check(HeapTupleGetDatum(tuple), false,
call_state->prodesc->result_typid,
&call_state->prodesc->domain_info,
- call_state->prodesc->fn_cxt);
+ call_state->prodesc->fn_cxt,
+ NULL);
return tuple;
}
diff --git a/src/test/modules/test_regex/test_regex.c b/src/test/modules/test_regex/test_regex.c
index d1dd48a993..fb8a22f891 100644
--- a/src/test/modules/test_regex/test_regex.c
+++ b/src/test/modules/test_regex/test_regex.c
@@ -679,7 +679,8 @@ build_test_info_result(regex_t *cpattern, test_re_flags *flags)
lbs[0] = 1;
/* XXX: this hardcodes assumptions about the text type */
return construct_md_array(elems, NULL, 1, dims, lbs,
- TEXTOID, -1, false, TYPALIGN_INT);
+ TEXTOID, -1, false, TYPALIGN_INT,
+ NULL);
}
/*
@@ -759,5 +760,6 @@ build_test_match_result(test_regex_ctx *matchctx)
lbs[0] = 1;
/* XXX: this hardcodes assumptions about the text type */
return construct_md_array(elems, nulls, 1, dims, lbs,
- TEXTOID, -1, false, TYPALIGN_INT);
+ TEXTOID, -1, false, TYPALIGN_INT,
+ NULL);
}
--
2.35.3