v6-0002-Add-EEOP_SUBTRANS-executor-step.patch
text/x-patch
Filename: v6-0002-Add-EEOP_SUBTRANS-executor-step.patch
Type: text/x-patch
Part: 1
Message:
Re: SQL/JSON features for v15
Patch
Format: format-patch
Series: patch v6-0002
Subject: Add EEOP_SUBTRANS executor step
| File | + | − |
|---|---|---|
| src/backend/executor/execExprInterp.c | 100 | 2 |
| src/backend/jit/llvm/llvmjit_expr.c | 84 | 6 |
| src/backend/jit/llvm/llvmjit_types.c | 1 | 0 |
| src/include/executor/execExpr.h | 13 | 0 |
From 45d938995ef8bab8049638a0ee63efbc9595ab45 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Mon, 15 Aug 2022 15:04:17 +0300
Subject: [PATCH v6 2/3] Add EEOP_SUBTRANS executor step
---
src/backend/executor/execExprInterp.c | 102 +++++++++++++++++++++++++-
src/backend/jit/llvm/llvmjit_expr.c | 90 +++++++++++++++++++++--
src/backend/jit/llvm/llvmjit_types.c | 1 +
src/include/executor/execExpr.h | 13 ++++
4 files changed, 198 insertions(+), 8 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 353346d5528..662d47f8cbb 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -158,6 +158,8 @@ static TupleDesc get_cached_rowtype(Oid type_id, int32 typmod,
bool *changed);
static void ExecEvalRowNullInt(ExprState *state, ExprEvalStep *op,
ExprContext *econtext, bool checkisnull);
+static void ExecEvalSubtransInterp(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
/* fast-path evaluation functions */
static Datum ExecJustInnerVar(ExprState *state, ExprContext *econtext, bool *isnull);
@@ -398,7 +400,8 @@ ExecReadyInterpretedExpr(ExprState *state)
* (Only applies when EEO_USE_COMPUTED_GOTO is defined.)
*/
static Datum
-ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
+ExecInterpExprStep(ExprState *state, int stepno,
+ ExprContext *econtext, bool *isnull)
{
ExprEvalStep *op;
TupleTableSlot *resultslot;
@@ -488,6 +491,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_GROUPING_FUNC,
&&CASE_EEOP_WINDOW_FUNC,
&&CASE_EEOP_SUBPLAN,
+ &&CASE_EEOP_SUBTRANS,
&&CASE_EEOP_JSON_CONSTRUCTOR,
&&CASE_EEOP_IS_JSON,
&&CASE_EEOP_JSONEXPR,
@@ -519,7 +523,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
#endif /* EEO_USE_COMPUTED_GOTO */
/* setup state */
- op = state->steps;
+ op = &state->steps[stepno];
resultslot = state->resultslot;
innerslot = econtext->ecxt_innertuple;
outerslot = econtext->ecxt_outertuple;
@@ -1827,6 +1831,16 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_NEXT();
}
+ EEO_CASE(EEOP_SUBTRANS)
+ {
+ /* too complex for an inline implementation */
+ if (ExecEvalSubtrans(state, op, econtext,
+ ExecEvalSubtransInterp))
+ EEO_JUMP(op->d.subtrans.jump_done);
+ else
+ EEO_JUMP(op->d.subtrans.jump_error);
+ }
+
EEO_CASE(EEOP_JSON_CONSTRUCTOR)
{
/* too complex for an inline implementation */
@@ -1861,6 +1875,12 @@ out:
return state->resvalue;
}
+static Datum
+ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
+{
+ return ExecInterpExprStep(state, 0, econtext, isnull);
+}
+
/*
* Expression evaluation callback that performs extra checks before executing
* the expression. Declared extern so other methods of execution can use it
@@ -4620,6 +4640,84 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
MemoryContextSwitchTo(oldContext);
}
+/*
+ * Execute subexpression steps using recursive interpreter call.
+ * "op" points EEOP_SUBTRANS step.
+ */
+static void
+ExecEvalSubtransInterp(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext)
+{
+ /* Recursively call interpreter for next step ignoring result */
+ bool isnull;
+
+ (void) ExecInterpExprStep(state, op - state->steps + 1, econtext,
+ &isnull);
+}
+
+/*
+ * Execute EEOP_SUBTRANS, calling "eval" function inside a
+ * subtransaction. This function executes sequence of subexpression
+ * steps that begins right after current step and ends with EEOP_DONE.
+ */
+bool
+ExecEvalSubtrans(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext, ExecEvalSubroutine eval)
+{
+ MemoryContext oldcontext = CurrentMemoryContext;
+ ResourceOwner oldowner = CurrentResourceOwner;
+ bool error;
+
+ /*
+ * We should catch exceptions of category ERRCODE_DATA_EXCEPTION and
+ * execute the corresponding ON ERROR behavior then.
+ */
+ BeginInternalSubTransaction(NULL);
+ /* Want to execute expressions inside function's memory context */
+ MemoryContextSwitchTo(oldcontext);
+
+ PG_TRY();
+ {
+ eval(state, op, econtext);
+
+ /* Commit the inner transaction, return to outer xact context */
+ ReleaseCurrentSubTransaction();
+ MemoryContextSwitchTo(oldcontext);
+ CurrentResourceOwner = oldowner;
+
+ error = false;
+ }
+ PG_CATCH();
+ {
+ ErrorData *edata;
+ int ecategory;
+
+ /* Save error info in oldcontext */
+ MemoryContextSwitchTo(oldcontext);
+ edata = CopyErrorData();
+ FlushErrorState();
+
+ /* Abort the inner transaction */
+ RollbackAndReleaseCurrentSubTransaction();
+ MemoryContextSwitchTo(oldcontext);
+ CurrentResourceOwner = oldowner;
+
+ ecategory = ERRCODE_TO_CATEGORY(edata->sqlerrcode);
+
+ if (ecategory != ERRCODE_DATA_EXCEPTION && /* jsonpath and other data errors */
+ ecategory != ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION) /* domain errors */
+ ReThrowError(edata);
+
+ *op->resvalue = (Datum) 0;
+ *op->resnull = true;
+
+ error = true;
+ }
+ PG_END_TRY();
+
+ return !error;
+}
+
/*
* Evaluate a JSON constructor expression.
*/
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index bd3965143da..614ed58f1cb 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -53,6 +53,8 @@ typedef struct CompiledExprState
static Datum ExecRunCompiledExpr(ExprState *state, ExprContext *econtext, bool *isNull);
+static void ExecEvalSubtransCompiled(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext);
static LLVMValueRef BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
LLVMModuleRef mod, FunctionCallInfo fcinfo,
@@ -72,10 +74,10 @@ static LLVMValueRef create_LifetimeEnd(LLVMModuleRef mod);
/*
- * JIT compile expression.
+ * JIT compile expression staring from the specified step.
*/
-bool
-llvm_compile_expr(ExprState *state)
+static bool
+llvm_compile_expr_step(ExprState *state, int start_opno)
{
PlanState *parent = state->parent;
char *funcname;
@@ -224,13 +226,13 @@ llvm_compile_expr(ExprState *state)
/* allocate blocks for each op upfront, so we can do jumps easily */
opblocks = palloc(sizeof(LLVMBasicBlockRef) * state->steps_len);
- for (int opno = 0; opno < state->steps_len; opno++)
+ for (int opno = start_opno; opno < state->steps_len; opno++)
opblocks[opno] = l_bb_append_v(eval_fn, "b.op.%d.start", opno);
/* jump from entry to first block */
- LLVMBuildBr(b, opblocks[0]);
+ LLVMBuildBr(b, opblocks[start_opno]);
- for (int opno = 0; opno < state->steps_len; opno++)
+ for (int opno = start_opno; opno < state->steps_len; opno++)
{
ExprEvalStep *op;
ExprEvalOp opcode;
@@ -2395,6 +2397,62 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]);
break;
+ case EEOP_SUBTRANS:
+ {
+ ExprState *substate;
+ LLVMValueRef v_ret;
+ LLVMTypeRef v_functype;
+
+ /* Create subexpression ExprState */
+ substate = makeNode(ExprState);
+ substate->parent = state->parent;
+ substate->steps = state->steps;
+ substate->steps_len = op->d.subtrans.jump_next;
+
+ /*
+ * Compile it starting from the first subexpression
+ * step, which is the next step.
+ */
+ llvm_compile_expr_step(substate, opno + 1);
+
+ /*
+ * Save subexpression state in the private area of
+ * the step.
+ */
+ op->d.subtrans.private_data = substate;
+
+ /*
+ * Call ExecEvalJsonExprSubtrans() passing
+ * ExecEvalSubtransCompiled(), which will execute
+ * subexpression getting ExprState from the private
+ * area.
+ */
+ v_functype = llvm_pg_var_func_type("TypeExecEvalSubroutine");
+
+ v_ret = build_EvalXFunc(b, mod, "ExecEvalSubtrans",
+ v_state, op, v_econtext,
+ l_ptr_const(ExecEvalSubtransCompiled,
+ LLVMPointerType(v_functype, 0)));
+ v_ret = LLVMBuildZExt(b, v_ret, TypeStorageBool, "");
+
+ /*
+ * Jump to "error" or "done" steps depending of
+ * returned boolean value (TRUE means "done").
+ */
+ LLVMBuildCondBr(b,
+ LLVMBuildICmp(b,
+ LLVMIntEQ,
+ v_ret,
+ l_sbool_const(0),
+ ""),
+ opblocks[op->d.subtrans.jump_error],
+ opblocks[op->d.subtrans.jump_done]);
+
+ /* Skip subexpression steps */
+ opno = op->d.subtrans.jump_next - 1;
+ break;
+ }
+
case EEOP_JSON_CONSTRUCTOR:
build_EvalXFunc(b, mod, "ExecEvalJsonConstructor",
v_state, op, v_econtext);
@@ -2447,6 +2505,15 @@ llvm_compile_expr(ExprState *state)
return true;
}
+/*
+ * JIT compile expression staring from the first step.
+ */
+bool
+llvm_compile_expr(ExprState *state)
+{
+ return llvm_compile_expr_step(state, 0);
+}
+
/*
* Run compiled expression.
*
@@ -2475,6 +2542,17 @@ ExecRunCompiledExpr(ExprState *state, ExprContext *econtext, bool *isNull)
return func(state, econtext, isNull);
}
+/* Execute subexpression steps using compiled ExprState */
+static void
+ExecEvalSubtransCompiled(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext)
+{
+ ExprState *substate = op->d.subtrans.private_data;
+ bool isnull;
+
+ (void) ExecEvalExpr(substate, econtext, &isnull);
+}
+
static LLVMValueRef
BuildV1Call(LLVMJitContext *context, LLVMBuilderRef b,
LLVMModuleRef mod, FunctionCallInfo fcinfo,
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 373471ad27f..a9ddba6e4cd 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -133,6 +133,7 @@ void *referenced_functions[] =
ExecEvalSysVar,
ExecEvalWholeRowVar,
ExecEvalXmlExpr,
+ ExecEvalSubtrans,
ExecEvalJsonConstructor,
ExecEvalJsonIsPredicate,
ExecEvalJson,
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index de9bbd2abcd..14064dd9521 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -242,6 +242,7 @@ typedef enum ExprEvalOp
EEOP_GROUPING_FUNC,
EEOP_WINDOW_FUNC,
EEOP_SUBPLAN,
+ EEOP_SUBTRANS,
EEOP_JSON_CONSTRUCTOR,
EEOP_IS_JSON,
EEOP_JSONEXPR,
@@ -680,6 +681,15 @@ typedef struct ExprEvalStep
int setoff;
} agg_trans;
+ /* for EEOP_SUBTRANS */
+ struct
+ {
+ void *private_data;
+ int jump_done;
+ int jump_error;
+ int jump_next;
+ } subtrans;
+
/* for EEOP_JSON_CONSTRUCTOR */
struct
{
@@ -866,6 +876,9 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op,
ExprContext *econtext, TupleTableSlot *slot);
+extern bool ExecEvalSubtrans(ExprState *state, ExprEvalStep *op,
+ ExprContext *econtext,
+ ExecEvalSubroutine func);
extern void ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
--
2.25.1