simple-expr-fix-2.patch
text/x-patch
Filename: simple-expr-fix-2.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: unified
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/pl_exec.c | 0 | 0 |
| src/pl/plpgsql/src/plpgsql.h | 0 | 0 |
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 9929e04e57bbc7d08938765b7f506c05c07b772b..1f40f3cf69234ff650ece2ccb09791f8e075ec1a 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** loop_exit:
*** 4491,4497 ****
* a Datum by directly calling ExecEvalExpr().
*
* If successful, store results into *result, *isNull, *rettype and return
! * TRUE. If the expression is not simple (any more), return FALSE.
*
* It is possible though unlikely for a simple expression to become non-simple
* (consider for example redefining a trivial view). We must handle that for
--- 4491,4508 ----
* a Datum by directly calling ExecEvalExpr().
*
* If successful, store results into *result, *isNull, *rettype and return
! * TRUE. If the expression cannot be handled by simple evaluation,
! * return FALSE.
! *
! * Because we only store one execution tree for a simple expression, we
! * can't handle recursion cases. So, if we see the tree is already busy
! * with an evaluation in the current xact, we just return FALSE and let the
! * caller run the expression the hard way. (Other alternatives such as
! * creating a new tree for a recursive call either introduce memory leaks,
! * or add enough bookkeeping to be doubtful wins anyway.) Another case that
! * is covered by the expr_simple_in_use test is where a previous execution
! * of the tree was aborted by an error: the tree may contain bogus state
! * so we dare not re-use it.
*
* It is possible though unlikely for a simple expression to become non-simple
* (consider for example redefining a trivial view). We must handle that for
*************** exec_eval_simple_expr(PLpgSQL_execstate
*** 4528,4533 ****
--- 4539,4550 ----
return false;
/*
+ * If expression is in use in current xact, don't touch it.
+ */
+ if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid)
+ return false;
+
+ /*
* Revalidate cached plan, so that we will notice if it became stale. (We
* also need to hold a refcount while using the plan.) Note that even if
* replanning occurs, the length of plancache_list can't change, since it
*************** exec_eval_simple_expr(PLpgSQL_execstate
*** 4562,4567 ****
--- 4579,4585 ----
{
expr->expr_simple_state = ExecPrepareExpr(expr->expr_simple_expr,
simple_eval_estate);
+ expr->expr_simple_in_use = false;
expr->expr_simple_lxid = curlxid;
}
*************** exec_eval_simple_expr(PLpgSQL_execstate
*** 4597,4602 ****
--- 4615,4625 ----
econtext->ecxt_param_list_info = paramLI;
/*
+ * Mark expression as busy for the duration of the ExecEvalExpr call.
+ */
+ expr->expr_simple_in_use = true;
+
+ /*
* Finally we can call the executor to evaluate the expression
*/
*result = ExecEvalExpr(expr->expr_simple_state,
*************** exec_eval_simple_expr(PLpgSQL_execstate
*** 4605,4610 ****
--- 4628,4635 ----
NULL);
/* Assorted cleanup */
+ expr->expr_simple_in_use = false;
+
estate->cur_expr = save_cur_expr;
if (!estate->readonly_func)
*************** exec_simple_check_plan(PLpgSQL_expr *exp
*** 5341,5346 ****
--- 5366,5372 ----
*/
expr->expr_simple_expr = tle->expr;
expr->expr_simple_state = NULL;
+ expr->expr_simple_in_use = false;
expr->expr_simple_lxid = InvalidLocalTransactionId;
/* Also stash away the expression result type */
expr->expr_simple_type = exprType((Node *) tle->expr);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 5b174c49b8bcac4658ffd54fc4493e43221533e7..155796be0f5b2d1ad7850f5734fc6363d3c58c15 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef struct PLpgSQL_expr
*** 214,223 ****
/*
* if expr is simple AND prepared in current transaction,
! * expr_simple_state is valid. Test validity by seeing if expr_simple_lxid
! * matches current LXID.
*/
! ExprState *expr_simple_state;
LocalTransactionId expr_simple_lxid;
} PLpgSQL_expr;
--- 214,225 ----
/*
* if expr is simple AND prepared in current transaction,
! * expr_simple_state and expr_simple_in_use are valid. Test validity by
! * seeing if expr_simple_lxid matches current LXID. (If not,
! * expr_simple_state probably points at garbage!)
*/
! ExprState *expr_simple_state; /* eval tree for expr_simple_expr */
! bool expr_simple_in_use; /* true if eval tree is active */
LocalTransactionId expr_simple_lxid;
} PLpgSQL_expr;