@@ -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,11 +143,14 @@ 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 ;
151+ Oid save_userid ;
152+ int save_sec_context ;
153+ int save_nestlevel ;
150154
151155/* Determine strength of lock needed. */
152156concurrent = stmt -> concurrent ;
@@ -231,14 +235,25 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
231235 */
232236SetMatViewPopulatedState (matviewRel , !stmt -> skipData );
233237
238+ relowner = matviewRel -> rd_rel -> relowner ;
239+
240+ /*
241+ * Switch to the owner's userid, so that any functions are run as that
242+ * user. Also arrange to make GUC variable changes local to this command.
243+ * Don't lock it down too tight to create a temporary table just yet. We
244+ * will switch modes when we are about to execute user code.
245+ */
246+ GetUserIdAndSecContext (& save_userid ,& save_sec_context );
247+ SetUserIdAndSecContext (relowner ,
248+ save_sec_context |SECURITY_LOCAL_USERID_CHANGE );
249+ save_nestlevel = NewGUCNestLevel ();
250+
234251/* Concurrent refresh builds new data in temp tablespace, and does diff. */
235252if (concurrent )
236253tableSpace = GetDefaultTablespace (RELPERSISTENCE_TEMP );
237254else
238255tableSpace = matviewRel -> rd_rel -> reltablespace ;
239256
240- owner = matviewRel -> rd_rel -> relowner ;
241-
242257/*
243258 * Create the transient table that will receive the regenerated data. Lock
244259 * it against access by any other process until commit (by which time it
@@ -249,9 +264,15 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
249264LockRelationOid (OIDNewHeap ,AccessExclusiveLock );
250265dest = CreateTransientRelDestReceiver (OIDNewHeap );
251266
267+ /*
268+ * Now lock down security-restricted operations.
269+ */
270+ SetUserIdAndSecContext (relowner ,
271+ save_sec_context |SECURITY_RESTRICTED_OPERATION );
272+
252273/* Generate the data, if wanted. */
253274if (!stmt -> skipData )
254- refresh_matview_datafill (dest ,dataQuery ,queryString , owner );
275+ refresh_matview_datafill (dest ,dataQuery ,queryString );
255276
256277heap_close (matviewRel ,NoLock );
257278
@@ -262,7 +283,8 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
262283
263284PG_TRY ();
264285{
265- refresh_by_match_merge (matviewOid ,OIDNewHeap );
286+ refresh_by_match_merge (matviewOid ,OIDNewHeap ,relowner ,
287+ save_sec_context );
266288}
267289PG_CATCH ();
268290{
@@ -274,33 +296,26 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
274296}
275297else
276298refresh_by_heap_swap (matviewOid ,OIDNewHeap );
299+
300+ /* Roll back any GUC changes */
301+ AtEOXact_GUC (false,save_nestlevel );
302+
303+ /* Restore userid and security context */
304+ SetUserIdAndSecContext (save_userid ,save_sec_context );
277305}
278306
279307/*
280308 * refresh_matview_datafill
281309 */
282310static void
283311refresh_matview_datafill (DestReceiver * dest ,Query * query ,
284- const char * queryString , Oid relowner )
312+ const char * queryString )
285313{
286314List * rewritten ;
287315PlannedStmt * plan ;
288316QueryDesc * queryDesc ;
289- Oid save_userid ;
290- int save_sec_context ;
291- int save_nestlevel ;
292317Query * copied_query ;
293318
294- /*
295- * Switch to the owner's userid, so that any functions are run as that
296- * user. Also lock down security-restricted operations and arrange to
297- * make GUC variable changes local to this command.
298- */
299- GetUserIdAndSecContext (& save_userid ,& save_sec_context );
300- SetUserIdAndSecContext (relowner ,
301- save_sec_context |SECURITY_RESTRICTED_OPERATION );
302- save_nestlevel = NewGUCNestLevel ();
303-
304319/* Lock and rewrite, using a copy to preserve the original query. */
305320copied_query = copyObject (query );
306321AcquireRewriteLocks (copied_query , true, false);
@@ -344,12 +359,6 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
344359FreeQueryDesc (queryDesc );
345360
346361PopActiveSnapshot ();
347-
348- /* Roll back any GUC changes */
349- AtEOXact_GUC (false,save_nestlevel );
350-
351- /* Restore userid and security context */
352- SetUserIdAndSecContext (save_userid ,save_sec_context );
353362}
354363
355364DestReceiver *
@@ -520,7 +529,8 @@ mv_GenerateOper(StringInfo buf, Oid opoid)
520529 * this command.
521530 */
522531static void
523- refresh_by_match_merge (Oid matviewOid ,Oid tempOid )
532+ refresh_by_match_merge (Oid matviewOid ,Oid tempOid ,Oid relowner ,
533+ int save_sec_context )
524534{
525535StringInfoData querybuf ;
526536Relation matviewRel ;
@@ -534,9 +544,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
534544ListCell * indexoidscan ;
535545int16 relnatts ;
536546bool * usedForQual ;
537- Oid save_userid ;
538- int save_sec_context ;
539- int save_nestlevel ;
540547
541548initStringInfo (& querybuf );
542549matviewRel = heap_open (matviewOid ,NoLock );
@@ -587,6 +594,9 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
587594SPI_getvalue (SPI_tuptable -> vals [0 ],SPI_tuptable -> tupdesc ,1 ))));
588595}
589596
597+ SetUserIdAndSecContext (relowner ,
598+ save_sec_context |SECURITY_LOCAL_USERID_CHANGE );
599+
590600/* Start building the query for creating the diff table. */
591601resetStringInfo (& querybuf );
592602appendStringInfo (& querybuf ,
@@ -681,9 +691,12 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
681691if (SPI_exec (querybuf .data ,0 )!= SPI_OK_UTILITY )
682692elog (ERROR ,"SPI_exec failed: %s" ,querybuf .data );
683693
694+ SetUserIdAndSecContext (relowner ,
695+ save_sec_context |SECURITY_RESTRICTED_OPERATION );
696+
684697/*
685698 * We have no further use for data from the "full-data" temp table, but we
686- * must keep it around because its type isreference from the diff table.
699+ * must keep it around because its type isreferenced from the diff table.
687700 */
688701
689702/* Analyze the diff table. */
@@ -694,16 +707,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
694707
695708OpenMatViewIncrementalMaintenance ();
696709
697- /*
698- * Switch to the owner's userid, so that any functions are run as that
699- * user. Also lock down security-restricted operations and arrange to
700- * make GUC variable changes local to this command.
701- */
702- GetUserIdAndSecContext (& save_userid ,& save_sec_context );
703- SetUserIdAndSecContext (matviewRel -> rd_rel -> relowner ,
704- save_sec_context |SECURITY_RESTRICTED_OPERATION );
705- save_nestlevel = NewGUCNestLevel ();
706-
707710/* Deletes must come before inserts; do them first. */
708711resetStringInfo (& querybuf );
709712appendStringInfo (& querybuf ,
@@ -724,12 +727,6 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid)
724727if (SPI_exec (querybuf .data ,0 )!= SPI_OK_INSERT )
725728elog (ERROR ,"SPI_exec failed: %s" ,querybuf .data );
726729
727- /* Roll back any GUC changes */
728- AtEOXact_GUC (false,save_nestlevel );
729-
730- /* Restore userid and security context */
731- SetUserIdAndSecContext (save_userid ,save_sec_context );
732-
733730/* We're done maintaining the materialized view. */
734731CloseMatViewIncrementalMaintenance ();
735732heap_close (tempRel ,NoLock );