On Tue, 06 Aug 2024 11:24:03 -0700
Jeff Davis <pg...@j-davis.com> wrote:

> On Wed, 2024-08-07 at 03:06 +0900, Yugo Nagata wrote:
> > I'm sorry. After sending the mail, I found the patch didn't work.
> > If we call RestrictSearchPath() before creating a relation, it tries
> > to create the relation in pg_catalog and it causes an error.
> 
> Yeah, that's exactly the problem I ran into in ExecCreateTableAs(),
> which was the reason I refactored it to use RefreshMatViewByOid().

I came up with an idea that we can rewrite into->rel to add the
current schemaname before calling RestrictSearchPath() as in the
attached patch.

It seems a simpler fix at least, but I am not sure whether this design
is better than using RefreshMatViewByOid from EXPLAIN considering
to support EXPLAIN REFRESH ...

Regards,
Yugo Nagata

-- 
Yugo NAGATA <nag...@sraoss.co.jp>
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 5771aabf40..1d06a7e96e 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -15,6 +15,7 @@
 
 #include "access/xact.h"
 #include "catalog/pg_type.h"
+#include "catalog/namespace.h"
 #include "commands/createas.h"
 #include "commands/defrem.h"
 #include "commands/prepare.h"
@@ -22,6 +23,7 @@
 #include "jit/jit.h"
 #include "libpq/pqformat.h"
 #include "libpq/protocol.h"
+#include "miscadmin.h"
 #include "nodes/extensible.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
@@ -467,6 +469,10 @@ standard_ExplainOneQuery(Query *query, int cursorOptions,
 	MemoryContext planner_ctx = NULL;
 	MemoryContext saved_ctx = NULL;
 
+	Oid			save_userid = InvalidOid;
+	int			save_sec_context = 0;
+	int			save_nestlevel = 0;
+
 	if (es->memory)
 	{
 		/*
@@ -487,6 +493,24 @@ standard_ExplainOneQuery(Query *query, int cursorOptions,
 		bufusage_start = pgBufferUsage;
 	INSTR_TIME_SET_CURRENT(planstart);
 
+	/*
+	 * For CREATE MATERIALIZED VIEW command, switch to the owner's userid, so
+	 * that any functions are run as that user.  Also lock down security-restricted
+	 * operations and arrange to make GUC variable changes local to this command.
+	 */
+	if (into && into->viewQuery)
+	{
+		Oid	nspid = RangeVarGetCreationNamespace(into->rel);
+
+		into->rel = makeRangeVar(get_namespace_name(nspid), into->rel->relname, -1);
+
+		GetUserIdAndSecContext(&save_userid, &save_sec_context);
+		SetUserIdAndSecContext(save_userid,
+							   save_sec_context | SECURITY_RESTRICTED_OPERATION);
+		save_nestlevel = NewGUCNestLevel();
+		RestrictSearchPath();
+	}
+
 	/* plan the query */
 	plan = pg_plan_query(query, queryString, cursorOptions, params);
 
@@ -510,6 +534,16 @@ standard_ExplainOneQuery(Query *query, int cursorOptions,
 	ExplainOnePlan(plan, into, es, queryString, params, queryEnv,
 				   &planduration, (es->buffers ? &bufusage : NULL),
 				   es->memory ? &mem_counters : NULL);
+
+	/* CREATE MATERIALIZED VIEW command */
+	if (into && into->viewQuery)
+	{
+		/* Roll back any GUC changes */
+		AtEOXact_GUC(false, save_nestlevel);
+
+		/* Restore userid and security context */
+		SetUserIdAndSecContext(save_userid, save_sec_context);
+	}
 }
 
 /*

Reply via email to