v7-0019-invent-some-error-safe-functions.patch
text/x-patch
Filename: v7-0019-invent-some-error-safe-functions.patch
Type: text/x-patch
Part: 0
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 v7-0019
Subject: invent some error safe functions
| File | + | − |
|---|---|---|
| src/backend/executor/execExpr.c | 41 | 0 |
| src/backend/optimizer/util/clauses.c | 69 | 0 |
| src/backend/parser/parse_type.c | 14 | 0 |
| src/backend/utils/fmgr/fmgr.c | 13 | 0 |
| src/include/executor/executor.h | 1 | 0 |
| src/include/fmgr.h | 3 | 0 |
| src/include/optimizer/optimizer.h | 2 | 0 |
| src/include/parser/parse_type.h | 2 | 0 |
From a70d65ce8183eef768eba2e340b208743539ddd5 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 10 Oct 2025 18:57:21 +0800
Subject: [PATCH v7 19/20] invent some error safe functions
stringTypeDatumSafe: error safe version of stringTypeDatum
evaluate_expr_safe: error safe version of evaluate_expr
ExecInitExprSafe: soft error variant of ExecInitExpr
OidInputFunctionCallSafe: soft error variant of OidInputFunctionCall
discussion: https://postgr.es/m/CADkLM=fv1JfY4Ufa-jcwwNbjQixNViskQ8jZu3Tz_p656i_4hQ@mail.gmail.com
---
src/backend/executor/execExpr.c | 41 +++++++++++++++++
src/backend/optimizer/util/clauses.c | 69 ++++++++++++++++++++++++++++
src/backend/parser/parse_type.c | 14 ++++++
src/backend/utils/fmgr/fmgr.c | 13 ++++++
src/include/executor/executor.h | 1 +
src/include/fmgr.h | 3 ++
src/include/optimizer/optimizer.h | 2 +
src/include/parser/parse_type.h | 2 +
8 files changed, 145 insertions(+)
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index f1569879b52..b302be36f73 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -170,6 +170,47 @@ ExecInitExpr(Expr *node, PlanState *parent)
return state;
}
+/*
+ * ExecInitExprSafe: soft error variant of ExecInitExpr.
+ *
+ * use it only for expression nodes support soft errors, not all expression
+ * nodes support it.
+*/
+ExprState *
+ExecInitExprSafe(Expr *node, PlanState *parent)
+{
+ ExprState *state;
+ ExprEvalStep scratch = {0};
+
+ /* Special case: NULL expression produces a NULL ExprState pointer */
+ if (node == NULL)
+ return NULL;
+
+ /* Initialize ExprState with empty step list */
+ state = makeNode(ExprState);
+ state->expr = node;
+ state->parent = parent;
+ state->ext_params = NULL;
+ state->escontext = makeNode(ErrorSaveContext);
+ state->escontext->type = T_ErrorSaveContext;
+ state->escontext->error_occurred = false;
+ state->escontext->details_wanted = false;
+
+ /* Insert setup steps as needed */
+ ExecCreateExprSetupSteps(state, (Node *) node);
+
+ /* Compile the expression proper */
+ ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
+
+ /* Finally, append a DONE step */
+ scratch.opcode = EEOP_DONE_RETURN;
+ ExprEvalPushStep(state, &scratch);
+
+ ExecReadyExpr(state);
+
+ return state;
+}
+
/*
* ExecInitExprWithParams: prepare a standalone expression tree for execution
*
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 81d768ff2a2..3f9ff455ba6 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -5147,6 +5147,75 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
resultTypByVal);
}
+/*
+ * evaluate_expr_safe: error safe version of evaluate_expr
+ *
+ * We use the executor's routine ExecEvalExpr() to avoid duplication of
+ * code and ensure we get the same result as the executor would get.
+ *
+ * return NULL when evaulation failed. Ensure the expression expr can be evaulated
+ * in a soft error way.
+ *
+ * See comments on evaluate_expr too.
+ */
+Expr *
+evaluate_expr_safe(Expr *expr, Oid result_type, int32 result_typmod,
+ Oid result_collation)
+{
+ EState *estate;
+ ExprState *exprstate;
+ MemoryContext oldcontext;
+ Datum const_val;
+ bool const_is_null;
+ int16 resultTypLen;
+ bool resultTypByVal;
+
+ estate = CreateExecutorState();
+
+ /* We can use the estate's working context to avoid memory leaks. */
+ oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+
+ /* Make sure any opfuncids are filled in. */
+ fix_opfuncids((Node *) expr);
+
+ /*
+ * Prepare expr for execution. (Note: we can't use ExecPrepareExpr
+ * because it'd result in recursively invoking eval_const_expressions.)
+ */
+ exprstate = ExecInitExprSafe(expr, NULL);
+
+ const_val = ExecEvalExprSwitchContext(exprstate,
+ GetPerTupleExprContext(estate),
+ &const_is_null);
+
+ /* Get info needed about result datatype */
+ get_typlenbyval(result_type, &resultTypLen, &resultTypByVal);
+
+ /* Get back to outer memory context */
+ MemoryContextSwitchTo(oldcontext);
+
+ if (SOFT_ERROR_OCCURRED(exprstate->escontext))
+ {
+ FreeExecutorState(estate);
+ return NULL;
+ }
+
+ if (!const_is_null)
+ {
+ if (resultTypLen == -1)
+ const_val = PointerGetDatum(PG_DETOAST_DATUM_COPY(const_val));
+ else
+ const_val = datumCopy(const_val, resultTypByVal, resultTypLen);
+ }
+
+ FreeExecutorState(estate);
+
+ return (Expr *) makeConst(result_type, result_typmod, result_collation,
+ resultTypLen,
+ const_val, const_is_null,
+ resultTypByVal);
+}
+
/*
* inline_set_returning_function
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index 7713bdc6af0..d260aeec5dc 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -19,6 +19,7 @@
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "nodes/makefuncs.h"
+#include "nodes/miscnodes.h"
#include "parser/parse_type.h"
#include "parser/parser.h"
#include "utils/array.h"
@@ -660,6 +661,19 @@ stringTypeDatum(Type tp, char *string, int32 atttypmod)
return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
}
+/* error safe version of stringTypeDatum */
+bool
+stringTypeDatumSafe(Type tp, char *string, int32 atttypmod, Datum *result)
+{
+ Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
+ Oid typinput = typform->typinput;
+ Oid typioparam = getTypeIOParam(tp);
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
+
+ return OidInputFunctionCallSafe(typinput, string, typioparam, atttypmod,
+ (Node *) &escontext, result);
+}
+
/*
* Given a typeid, return the type's typrelid (associated relation), if any.
* Returns InvalidOid if type is not a composite type.
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 0fe63c6bb83..aaa4a42b1ea 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -1759,6 +1759,19 @@ OidInputFunctionCall(Oid functionId, char *str, Oid typioparam, int32 typmod)
return InputFunctionCall(&flinfo, str, typioparam, typmod);
}
+bool
+OidInputFunctionCallSafe(Oid functionId, char *str, Oid typioparam,
+ int32 typmod, Node *escontext,
+ Datum *result)
+{
+ FmgrInfo flinfo;
+
+ fmgr_info(functionId, &flinfo);
+
+ return InputFunctionCallSafe(&flinfo, str, typioparam, typmod,
+ escontext, result);
+}
+
char *
OidOutputFunctionCall(Oid functionId, Datum val)
{
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 3248e78cd28..ff9997e1cc1 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -321,6 +321,7 @@ ExecProcNode(PlanState *node)
* prototypes from functions in execExpr.c
*/
extern ExprState *ExecInitExpr(Expr *node, PlanState *parent);
+extern ExprState *ExecInitExprSafe(Expr *node, PlanState *parent);
extern ExprState *ExecInitExprWithParams(Expr *node, ParamListInfo ext_params);
extern ExprState *ExecInitQual(List *qual, PlanState *parent);
extern ExprState *ExecInitCheck(List *qual, PlanState *parent);
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 74fe3ea0575..991e14034d3 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -750,6 +750,9 @@ extern bool DirectInputFunctionCallSafe(PGFunction func, char *str,
Datum *result);
extern Datum OidInputFunctionCall(Oid functionId, char *str,
Oid typioparam, int32 typmod);
+extern bool OidInputFunctionCallSafe(Oid functionId, char *str, Oid typioparam,
+ int32 typmod, Node *escontext,
+ Datum *result);
extern char *OutputFunctionCall(FmgrInfo *flinfo, Datum val);
extern char *OidOutputFunctionCall(Oid functionId, Datum val);
extern Datum ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
diff --git a/src/include/optimizer/optimizer.h b/src/include/optimizer/optimizer.h
index a34113903c0..f1b6381d084 100644
--- a/src/include/optimizer/optimizer.h
+++ b/src/include/optimizer/optimizer.h
@@ -146,6 +146,8 @@ extern Node *estimate_expression_value(PlannerInfo *root, Node *node);
extern Expr *evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
Oid result_collation);
+extern Expr *evaluate_expr_safe(Expr *expr, Oid result_type, int32 result_typmod,
+ Oid result_collation);
extern bool var_is_nonnullable(PlannerInfo *root, Var *var, bool use_rel_info);
extern List *expand_function_arguments(List *args, bool include_out_arguments,
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 0d919d8bfa2..12381aed64c 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -47,6 +47,8 @@ extern char *typeTypeName(Type t);
extern Oid typeTypeRelid(Type typ);
extern Oid typeTypeCollation(Type typ);
extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
+extern bool stringTypeDatumSafe(Type tp, char *string, int32 atttypmod,
+ Datum *result);
extern Oid typeidTypeRelid(Oid type_id);
extern Oid typeOrDomainTypeRelid(Oid type_id);
--
2.34.1