aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pl/plpgsql/src/pl_exec.c20
-rw-r--r--src/pl/plpgsql/src/plpgsql.h1
2 files changed, 16 insertions, 5 deletions
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index fd799b724da..4a9ed83030a 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -6079,6 +6079,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
LocalTransactionId curlxid = MyProc->lxid;
CachedPlan *cplan;
void *save_setup_arg;
+ bool need_snapshot;
MemoryContext oldcontext;
/*
@@ -6150,12 +6151,19 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
/*
* We have to do some of the things SPI_execute_plan would do, in
- * particular advance the snapshot if we are in a non-read-only function.
- * Without this, stable functions within the expression would fail to see
- * updates made so far by our own function.
+ * particular push a new snapshot so that stable functions within the
+ * expression can see updates made so far by our own function. However,
+ * we can skip doing that (and just invoke the expression with the same
+ * snapshot passed to our function) in some cases, which is useful because
+ * it's quite expensive relative to the cost of a simple expression. We
+ * can skip it if the expression contains no stable or volatile functions;
+ * immutable functions shouldn't need to see our updates. Also, if this
+ * is a read-only function, we haven't made any updates so again it's okay
+ * to skip.
*/
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
- if (!estate->readonly_func)
+ need_snapshot = (expr->expr_simple_mutable && !estate->readonly_func);
+ if (need_snapshot)
{
CommandCounterIncrement();
PushActiveSnapshot(GetTransactionSnapshot());
@@ -6180,7 +6188,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
estate->paramLI->parserSetupArg = save_setup_arg;
- if (!estate->readonly_func)
+ if (need_snapshot)
PopActiveSnapshot();
MemoryContextSwitchTo(oldcontext);
@@ -8051,6 +8059,8 @@ exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
/* Also stash away the expression result type */
expr->expr_simple_type = exprType((Node *) tle_expr);
expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
+ /* We also want to remember if it is immutable or not */
+ expr->expr_simple_mutable = contain_mutable_functions((Node *) tle_expr);
}
/*
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index f66b2baa70a..6b40fcd1963 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -234,6 +234,7 @@ typedef struct PLpgSQL_expr
int expr_simple_generation; /* plancache generation we checked */
Oid expr_simple_type; /* result type Oid, if simple */
int32 expr_simple_typmod; /* result typmod, if simple */
+ bool expr_simple_mutable; /* true if simple expr is mutable */
/*
* if expr is simple AND prepared in current transaction,