mirror of
https://github.com/postgres/postgres.git
synced 2025-08-19 23:22:23 +03:00
Add soft error handling to some expression nodes
This adjusts the expression evaluation code for CoerceViaIO and CoerceToDomain to handle errors softly if needed. For CoerceViaIo, this means using InputFunctionCallSafe(), which provides the option to handle errors softly, instead of calling the type input function directly. For CoerceToDomain, this simply entails replacing the ereport() in ExecEvalConstraintCheck() by errsave(). In both cases, the ErrorSaveContext to be used when evaluating the expression is stored by ExecInitExprRec() in the expression's struct in the expression's ExprEvalStep. The ErrorSaveContext is passed by setting ExprState.escontext to point to it when calling ExecInitExprRec() on the expression whose errors are to be handled softly. Note that no call site of ExecInitExprRec() has been changed in this commit, so there's no functional change. This is intended for implementing new SQL/JSON expression nodes in future commits that will use to it suppress errors that may occur during type coercions. Reviewed-by: Álvaro Herrera Discussion: https://postgr.es/m/CA+HiwqE4XTdfb1nW=Ojoy_tQSRhYt-q_kb6i5d4xcKyrLC1Nbg@mail.gmail.com
This commit is contained in:
@@ -70,12 +70,14 @@ LLVMTypeRef StructHeapTupleTableSlot;
|
||||
LLVMTypeRef StructMinimalTupleTableSlot;
|
||||
LLVMTypeRef StructMemoryContextData;
|
||||
LLVMTypeRef StructFunctionCallInfoData;
|
||||
LLVMTypeRef StructFmgrInfo;
|
||||
LLVMTypeRef StructExprContext;
|
||||
LLVMTypeRef StructExprEvalStep;
|
||||
LLVMTypeRef StructExprState;
|
||||
LLVMTypeRef StructAggState;
|
||||
LLVMTypeRef StructAggStatePerGroupData;
|
||||
LLVMTypeRef StructAggStatePerTransData;
|
||||
LLVMTypeRef StructErrorSaveContext;
|
||||
|
||||
LLVMValueRef AttributeTemplate;
|
||||
|
||||
@@ -1118,6 +1120,7 @@ llvm_create_types(void)
|
||||
StructExprEvalStep = llvm_pg_var_type("StructExprEvalStep");
|
||||
StructExprState = llvm_pg_var_type("StructExprState");
|
||||
StructFunctionCallInfoData = llvm_pg_var_type("StructFunctionCallInfoData");
|
||||
StructFmgrInfo = llvm_pg_var_type("StructFmgrInfo");
|
||||
StructMemoryContextData = llvm_pg_var_type("StructMemoryContextData");
|
||||
StructTupleTableSlot = llvm_pg_var_type("StructTupleTableSlot");
|
||||
StructHeapTupleTableSlot = llvm_pg_var_type("StructHeapTupleTableSlot");
|
||||
@@ -1127,6 +1130,7 @@ llvm_create_types(void)
|
||||
StructAggState = llvm_pg_var_type("StructAggState");
|
||||
StructAggStatePerGroupData = llvm_pg_var_type("StructAggStatePerGroupData");
|
||||
StructAggStatePerTransData = llvm_pg_var_type("StructAggStatePerTransData");
|
||||
StructErrorSaveContext = llvm_pg_var_type("StructErrorSaveContext");
|
||||
|
||||
AttributeTemplate = LLVMGetNamedFunction(llvm_types_module, "AttributeTemplate");
|
||||
}
|
||||
|
@@ -1251,14 +1251,9 @@ llvm_compile_expr(ExprState *state)
|
||||
|
||||
case EEOP_IOCOERCE:
|
||||
{
|
||||
FunctionCallInfo fcinfo_out,
|
||||
fcinfo_in;
|
||||
LLVMValueRef v_fn_out,
|
||||
v_fn_in;
|
||||
LLVMValueRef v_fcinfo_out,
|
||||
v_fcinfo_in;
|
||||
LLVMValueRef v_fcinfo_in_isnullp;
|
||||
LLVMValueRef v_retval;
|
||||
FunctionCallInfo fcinfo_out;
|
||||
LLVMValueRef v_fn_out;
|
||||
LLVMValueRef v_fcinfo_out;
|
||||
LLVMValueRef v_resvalue;
|
||||
LLVMValueRef v_resnull;
|
||||
|
||||
@@ -1271,7 +1266,6 @@ llvm_compile_expr(ExprState *state)
|
||||
LLVMBasicBlockRef b_inputcall;
|
||||
|
||||
fcinfo_out = op->d.iocoerce.fcinfo_data_out;
|
||||
fcinfo_in = op->d.iocoerce.fcinfo_data_in;
|
||||
|
||||
b_skipoutput = l_bb_before_v(opblocks[opno + 1],
|
||||
"op.%d.skipoutputnull", opno);
|
||||
@@ -1283,14 +1277,7 @@ llvm_compile_expr(ExprState *state)
|
||||
"op.%d.inputcall", opno);
|
||||
|
||||
v_fn_out = llvm_function_reference(context, b, mod, fcinfo_out);
|
||||
v_fn_in = llvm_function_reference(context, b, mod, fcinfo_in);
|
||||
v_fcinfo_out = l_ptr_const(fcinfo_out, l_ptr(StructFunctionCallInfoData));
|
||||
v_fcinfo_in = l_ptr_const(fcinfo_in, l_ptr(StructFunctionCallInfoData));
|
||||
|
||||
v_fcinfo_in_isnullp =
|
||||
LLVMBuildStructGEP(b, v_fcinfo_in,
|
||||
FIELDNO_FUNCTIONCALLINFODATA_ISNULL,
|
||||
"v_fcinfo_in_isnull");
|
||||
|
||||
/* output functions are not called on nulls */
|
||||
v_resnull = LLVMBuildLoad(b, v_resnullp, "");
|
||||
@@ -1356,24 +1343,44 @@ llvm_compile_expr(ExprState *state)
|
||||
LLVMBuildBr(b, b_inputcall);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the input function.
|
||||
*
|
||||
* If op->d.iocoerce.escontext references an
|
||||
* ErrorSaveContext, InputFunctionCallSafe() would return
|
||||
* false upon encountering an error.
|
||||
*/
|
||||
LLVMPositionBuilderAtEnd(b, b_inputcall);
|
||||
/* set arguments */
|
||||
/* arg0: output */
|
||||
LLVMBuildStore(b, v_output,
|
||||
l_funcvaluep(b, v_fcinfo_in, 0));
|
||||
LLVMBuildStore(b, v_resnull,
|
||||
l_funcnullp(b, v_fcinfo_in, 0));
|
||||
{
|
||||
Oid ioparam = op->d.iocoerce.typioparam;
|
||||
LLVMValueRef v_params[6];
|
||||
LLVMValueRef v_success;
|
||||
|
||||
/* arg1: ioparam: preset in execExpr.c */
|
||||
/* arg2: typmod: preset in execExpr.c */
|
||||
v_params[0] = l_ptr_const(op->d.iocoerce.finfo_in,
|
||||
l_ptr(StructFmgrInfo));
|
||||
v_params[1] = v_output;
|
||||
v_params[2] = l_oid_const(lc, ioparam);
|
||||
v_params[3] = l_int32_const(lc, -1);
|
||||
v_params[4] = l_ptr_const(op->d.iocoerce.escontext,
|
||||
l_ptr(StructErrorSaveContext));
|
||||
|
||||
/* reset fcinfo_in->isnull */
|
||||
LLVMBuildStore(b, l_sbool_const(0), v_fcinfo_in_isnullp);
|
||||
/* and call function */
|
||||
v_retval = LLVMBuildCall(b, v_fn_in, &v_fcinfo_in, 1,
|
||||
"funccall_iocoerce_in");
|
||||
/*
|
||||
* InputFunctionCallSafe() will write directly into
|
||||
* *op->resvalue.
|
||||
*/
|
||||
v_params[5] = v_resvaluep;
|
||||
|
||||
LLVMBuildStore(b, v_retval, v_resvaluep);
|
||||
v_success = LLVMBuildCall(b, llvm_pg_func(mod, "InputFunctionCallSafe"),
|
||||
v_params, lengthof(v_params),
|
||||
"funccall_iocoerce_in_safe");
|
||||
|
||||
/*
|
||||
* Return null if InputFunctionCallSafe() encountered
|
||||
* an error.
|
||||
*/
|
||||
v_resnullp = LLVMBuildICmp(b, LLVMIntEQ, v_success,
|
||||
l_sbool_const(0), "");
|
||||
}
|
||||
|
||||
LLVMBuildBr(b, opblocks[opno + 1]);
|
||||
break;
|
||||
|
@@ -59,6 +59,7 @@ AggStatePerTransData StructAggStatePerTransData;
|
||||
ExprContext StructExprContext;
|
||||
ExprEvalStep StructExprEvalStep;
|
||||
ExprState StructExprState;
|
||||
FmgrInfo StructFmgrInfo;
|
||||
FunctionCallInfoBaseData StructFunctionCallInfoData;
|
||||
HeapTupleData StructHeapTupleData;
|
||||
MemoryContextData StructMemoryContextData;
|
||||
@@ -66,6 +67,7 @@ TupleTableSlot StructTupleTableSlot;
|
||||
HeapTupleTableSlot StructHeapTupleTableSlot;
|
||||
MinimalTupleTableSlot StructMinimalTupleTableSlot;
|
||||
TupleDescData StructTupleDescData;
|
||||
ErrorSaveContext StructErrorSaveContext;
|
||||
|
||||
|
||||
/*
|
||||
@@ -136,6 +138,7 @@ void *referenced_functions[] =
|
||||
ExecEvalJsonConstructor,
|
||||
ExecEvalJsonIsPredicate,
|
||||
MakeExpandedObjectReadOnlyInternal,
|
||||
InputFunctionCallSafe,
|
||||
slot_getmissingattrs,
|
||||
slot_getsomeattrs_int,
|
||||
strlen,
|
||||
|
Reference in New Issue
Block a user