@@ -59,12 +59,13 @@ static void transientrel_receive(TupleTableSlot *slot, DestReceiver *self);
5959static void transientrel_shutdown (DestReceiver * self );
6060static void transientrel_destroy (DestReceiver * self );
6161static void refresh_matview_datafill (DestReceiver * dest ,Query * query ,
62- const char * queryString , Oid relowner );
62+ const char * queryString );
6363
6464static char * make_temptable_name_n (char * tempname ,int n );
6565static void mv_GenerateOper (StringInfo buf ,Oid opoid );
6666
67- static void refresh_by_match_merge (Oid matviewOid ,Oid tempOid );
67+ static void refresh_by_match_merge (Oid matviewOid ,Oid tempOid ,Oid relowner ,
68+ int save_sec_context );
6869static void refresh_by_heap_swap (Oid matviewOid ,Oid OIDNewHeap );
6970
7071static void OpenMatViewIncrementalMaintenance (void );
@@ -142,12 +143,15 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
142143List * actions ;
143144Query * dataQuery ;
144145Oid tableSpace ;
145- Oid owner ;
146+ Oid relowner ;
146147Oid OIDNewHeap ;
147148DestReceiver * dest ;
148149bool concurrent ;
149150LOCKMODE lockmode ;
150151char relpersistence ;
152+ Oid save_userid ;
153+ int save_sec_context ;
154+ int save_nestlevel ;
151155
152156/* Determine strength of lock needed. */
153157concurrent = stmt -> concurrent ;
@@ -232,6 +236,19 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
232236 */
233237SetMatViewPopulatedState (matviewRel , !stmt -> skipData );
234238
239+ relowner = matviewRel -> rd_rel -> relowner ;
240+
241+ /*
242+ * Switch to the owner's userid, so that any functions are run as that
243+ * user. Also arrange to make GUC variable changes local to this command.
244+ * Don't lock it down too tight to create a temporary table just yet. We
245+ * will switch modes when we are about to execute user code.
246+ */
247+ GetUserIdAndSecContext (& save_userid ,& save_sec_context );
248+ SetUserIdAndSecContext (relowner ,
249+ save_sec_context |SECURITY_LOCAL_USERID_CHANGE );
250+ save_nestlevel = NewGUCNestLevel ();
251+
235252/* Concurrent refresh builds new data in temp tablespace, and does diff. */
236253if (concurrent )
237254{
@@ -244,8 +261,6 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
244261relpersistence = matviewRel -> rd_rel -> relpersistence ;
245262}
246263
247- owner = matviewRel -> rd_rel -> relowner ;
248-
249264/*
250265 * Create the transient table that will receive the regenerated data. Lock
251266 * it against access by any other process until commit (by which time it
@@ -256,9 +271,15 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
256271LockRelationOid (OIDNewHeap ,AccessExclusiveLock );
257272dest = CreateTransientRelDestReceiver (OIDNewHeap );
258273
274+ /*
275+ * Now lock down security-restricted operations.
276+ */
277+ SetUserIdAndSecContext (relowner ,
278+ save_sec_context |SECURITY_RESTRICTED_OPERATION );
279+
259280/* Generate the data, if wanted. */
260281if (!stmt -> skipData )
261- refresh_matview_datafill (dest ,dataQuery ,queryString , owner );
282+ refresh_matview_datafill (dest ,dataQuery ,queryString );
262283
263284heap_close (matviewRel ,NoLock );
264285
@@ -269,7 +290,8 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
269290
270291PG_TRY ();
271292{
272- refresh_by_match_merge (matviewOid ,OIDNewHeap );
293+ refresh_by_match_merge (matviewOid ,OIDNewHeap ,relowner ,
294+ save_sec_context );
273295}
274296PG_CATCH ();
275297{
@@ -282,6 +304,12 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
282304else
283305refresh_by_heap_swap (matviewOid ,OIDNewHeap );
284306
307+ /* Roll back any GUC changes */
308+ AtEOXact_GUC (false,save_nestlevel );
309+
310+ /* Restore userid and security context */
311+ SetUserIdAndSecContext (save_userid ,save_sec_context );
312+
285313return matviewOid ;
286314}
287315
@@ -290,26 +318,13 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
290318 */
291319static void
292320refresh_matview_datafill (DestReceiver * dest ,Query * query ,
293- const char * queryString , Oid relowner )
321+ const char * queryString )
294322{
295323List * rewritten ;
296324PlannedStmt * plan ;
297325QueryDesc * queryDesc ;
298- Oid save_userid ;
299- int save_sec_context ;
300- int save_nestlevel ;
301326Query * copied_query ;
302327
303- /*
304- * Switch to the owner's userid, so that any functions are run as that
305- * user. Also lock down security-restricted operations and arrange to
306- * make GUC variable changes local to this command.
307- */
308- GetUserIdAndSecContext (& save_userid ,& save_sec_context );
309- SetUserIdAndSecContext (relowner ,
310- save_sec_context |SECURITY_RESTRICTED_OPERATION );
311- save_nestlevel = NewGUCNestLevel ();
312-
313328/* Lock and rewrite, using a copy to preserve the original query. */
314329copied_query = copyObject (query );
315330AcquireRewriteLocks (copied_query , true, false);
@@ -353,12 +368,6 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
353368FreeQueryDesc (queryDesc );
354369
355370PopActiveSnapshot ();
356-
357- /* Roll back any GUC changes */
358- AtEOXact_GUC (false,save_nestlevel );
359-
360- /* Restore userid and security context */
361- SetUserIdAndSecContext (save_userid ,save_sec_context );
362371}
363372
364373DestReceiver *
@@ -529,7 +538,8 @@ mv_GenerateOper(StringInfo buf, Oid opoid)
529538 * this command.
530539 */
531540static void
532- refresh_by_match_merge (Oid matviewOid ,Oid tempOid )
541+ refresh_by_match_merge (Oid matviewOid ,Oid tempOid ,Oid relowner ,
542+ int save_sec_context )
533543{
534544StringInfoData querybuf ;
535545Relation matviewRel ;
@@ -543,9 +553,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
543553ListCell * indexoidscan ;
544554int16 relnatts ;
545555bool * usedForQual ;
546- Oid save_userid ;
547- int save_sec_context ;
548- int save_nestlevel ;
549556
550557initStringInfo (& querybuf );
551558matviewRel = heap_open (matviewOid ,NoLock );
@@ -596,6 +603,9 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
596603SPI_getvalue (SPI_tuptable -> vals [0 ],SPI_tuptable -> tupdesc ,1 ))));
597604}
598605
606+ SetUserIdAndSecContext (relowner ,
607+ save_sec_context |SECURITY_LOCAL_USERID_CHANGE );
608+
599609/* Start building the query for creating the diff table. */
600610resetStringInfo (& querybuf );
601611appendStringInfo (& querybuf ,
@@ -690,9 +700,12 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
690700if (SPI_exec (querybuf .data ,0 )!= SPI_OK_UTILITY )
691701elog (ERROR ,"SPI_exec failed: %s" ,querybuf .data );
692702
703+ SetUserIdAndSecContext (relowner ,
704+ save_sec_context |SECURITY_RESTRICTED_OPERATION );
705+
693706/*
694707 * We have no further use for data from the "full-data" temp table, but we
695- * must keep it around because its type isreference from the diff table.
708+ * must keep it around because its type isreferenced from the diff table.
696709 */
697710
698711/* Analyze the diff table. */
@@ -703,16 +716,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
703716
704717OpenMatViewIncrementalMaintenance ();
705718
706- /*
707- * Switch to the owner's userid, so that any functions are run as that
708- * user. Also lock down security-restricted operations and arrange to
709- * make GUC variable changes local to this command.
710- */
711- GetUserIdAndSecContext (& save_userid ,& save_sec_context );
712- SetUserIdAndSecContext (matviewRel -> rd_rel -> relowner ,
713- save_sec_context |SECURITY_RESTRICTED_OPERATION );
714- save_nestlevel = NewGUCNestLevel ();
715-
716719/* Deletes must come before inserts; do them first. */
717720resetStringInfo (& querybuf );
718721appendStringInfo (& querybuf ,
@@ -733,12 +736,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
733736if (SPI_exec (querybuf .data ,0 )!= SPI_OK_INSERT )
734737elog (ERROR ,"SPI_exec failed: %s" ,querybuf .data );
735738
736- /* Roll back any GUC changes */
737- AtEOXact_GUC (false,save_nestlevel );
738-
739- /* Restore userid and security context */
740- SetUserIdAndSecContext (save_userid ,save_sec_context );
741-
742739/* We're done maintaining the materialized view. */
743740CloseMatViewIncrementalMaintenance ();
744741heap_close (tempRel ,NoLock );