@ -547,21 +547,22 @@ DefineIndex(Oid relationId,
LOCKTAG heaplocktag ;
LOCKMODE lockmode ;
Snapshot snapshot ;
int save_nestlevel = - 1 ;
Oid root_save_userid ;
int root_save_sec_context ;
int root_save_nestlevel ;
int i ;
root_save_nestlevel = NewGUCNestLevel ( ) ;
/*
* Some callers need us to run with an empty default_tablespace ; this is a
* necessary hack to be able to reproduce catalog state accurately when
* recreating indexes after table - rewriting ALTER TABLE .
*/
if ( stmt - > reset_default_tblspc )
{
save_nestlevel = NewGUCNestLevel ( ) ;
( void ) set_config_option ( " default_tablespace " , " " ,
PGC_USERSET , PGC_S_SESSION ,
GUC_ACTION_SAVE , true , 0 , false ) ;
}
/*
* Force non - concurrent build on temporary relations , even if CONCURRENTLY
@ -640,6 +641,15 @@ DefineIndex(Oid relationId,
lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock ;
rel = table_open ( relationId , lockmode ) ;
/*
* Switch to the table owner ' s userid , so that any index functions are run
* as that user . Also lock down security - restricted operations . We
* already arranged to make GUC variable changes local to this command .
*/
GetUserIdAndSecContext ( & root_save_userid , & root_save_sec_context ) ;
SetUserIdAndSecContext ( rel - > rd_rel - > relowner ,
root_save_sec_context | SECURITY_RESTRICTED_OPERATION ) ;
namespaceId = RelationGetNamespace ( rel ) ;
/* Ensure that it makes sense to index this kind of relation */
@ -715,7 +725,7 @@ DefineIndex(Oid relationId,
{
AclResult aclresult ;
aclresult = pg_namespace_aclcheck ( namespaceId , GetUserId ( ) ,
aclresult = pg_namespace_aclcheck ( namespaceId , root_save_userid ,
ACL_CREATE ) ;
if ( aclresult ! = ACLCHECK_OK )
aclcheck_error ( aclresult , OBJECT_SCHEMA ,
@ -747,7 +757,7 @@ DefineIndex(Oid relationId,
{
AclResult aclresult ;
aclresult = pg_tablespace_aclcheck ( tablespaceId , GetUserId ( ) ,
aclresult = pg_tablespace_aclcheck ( tablespaceId , root_save_userid ,
ACL_CREATE ) ;
if ( aclresult ! = ACLCHECK_OK )
aclcheck_error ( aclresult , OBJECT_TABLESPACE ,
@ -1138,15 +1148,17 @@ DefineIndex(Oid relationId,
ObjectAddressSet ( address , RelationRelationId , indexRelationId ) ;
/*
* Revert to original default_tablespace . Must do this before any return
* from this function , but after index_create , so this is a good time .
*/
if ( save_nestlevel > = 0 )
AtEOXact_GUC ( true , save_nestlevel ) ;
if ( ! OidIsValid ( indexRelationId ) )
{
/*
* Roll back any GUC changes executed by index functions . Also revert
* to original default_tablespace if we changed it above .
*/
AtEOXact_GUC ( false , root_save_nestlevel ) ;
/* Restore userid and security context */
SetUserIdAndSecContext ( root_save_userid , root_save_sec_context ) ;
table_close ( rel , NoLock ) ;
/* If this is the top-level index, we're done */
@ -1156,6 +1168,17 @@ DefineIndex(Oid relationId,
return address ;
}
/*
* Roll back any GUC changes executed by index functions , and keep
* subsequent changes local to this command . It ' s barely possible that
* some index function changed a behavior - affecting GUC , e . g . xmloption ,
* that affects subsequent steps . This improves bug - compatibility with
* older PostgreSQL versions . They did the AtEOXact_GUC ( ) here for the
* purpose of clearing the above default_tablespace change .
*/
AtEOXact_GUC ( false , root_save_nestlevel ) ;
root_save_nestlevel = NewGUCNestLevel ( ) ;
/* Add any requested comment */
if ( stmt - > idxcomment ! = NULL )
CreateComments ( indexRelationId , RelationRelationId , 0 ,
@ -1202,6 +1225,9 @@ DefineIndex(Oid relationId,
{
Oid childRelid = part_oids [ i ] ;
Relation childrel ;
Oid child_save_userid ;
int child_save_sec_context ;
int child_save_nestlevel ;
List * childidxs ;
ListCell * cell ;
AttrMap * attmap ;
@ -1209,6 +1235,12 @@ DefineIndex(Oid relationId,
childrel = table_open ( childRelid , lockmode ) ;
GetUserIdAndSecContext ( & child_save_userid ,
& child_save_sec_context ) ;
SetUserIdAndSecContext ( childrel - > rd_rel - > relowner ,
child_save_sec_context | SECURITY_RESTRICTED_OPERATION ) ;
child_save_nestlevel = NewGUCNestLevel ( ) ;
/*
* Don ' t try to create indexes on foreign tables , though . Skip
* those if a regular index , or fail if trying to create a
@ -1224,6 +1256,9 @@ DefineIndex(Oid relationId,
errdetail ( " Table \" %s \" contains partitions that are foreign tables. " ,
RelationGetRelationName ( rel ) ) ) ) ;
AtEOXact_GUC ( false , child_save_nestlevel ) ;
SetUserIdAndSecContext ( child_save_userid ,
child_save_sec_context ) ;
table_close ( childrel , lockmode ) ;
continue ;
}
@ -1295,6 +1330,9 @@ DefineIndex(Oid relationId,
}
list_free ( childidxs ) ;
AtEOXact_GUC ( false , child_save_nestlevel ) ;
SetUserIdAndSecContext ( child_save_userid ,
child_save_sec_context ) ;
table_close ( childrel , NoLock ) ;
/*
@ -1351,12 +1389,21 @@ DefineIndex(Oid relationId,
if ( found_whole_row )
elog ( ERROR , " cannot convert whole-row table reference " ) ;
/*
* Recurse as the starting user ID . Callee will use that
* for permission checks , then switch again .
*/
Assert ( GetUserId ( ) = = child_save_userid ) ;
SetUserIdAndSecContext ( root_save_userid ,
root_save_sec_context ) ;
DefineIndex ( childRelid , childStmt ,
InvalidOid , /* no predefined OID */
indexRelationId , /* this is our child */
createdConstraintId ,
is_alter_table , check_rights , check_not_in_use ,
skip_build , quiet ) ;
SetUserIdAndSecContext ( child_save_userid ,
child_save_sec_context ) ;
}
pgstat_progress_update_param ( PROGRESS_CREATEIDX_PARTITIONS_DONE ,
@ -1393,12 +1440,17 @@ DefineIndex(Oid relationId,
* Indexes on partitioned tables are not themselves built , so we ' re
* done here .
*/
AtEOXact_GUC ( false , root_save_nestlevel ) ;
SetUserIdAndSecContext ( root_save_userid , root_save_sec_context ) ;
table_close ( rel , NoLock ) ;
if ( ! OidIsValid ( parentIndexId ) )
pgstat_progress_end_command ( ) ;
return address ;
}
AtEOXact_GUC ( false , root_save_nestlevel ) ;
SetUserIdAndSecContext ( root_save_userid , root_save_sec_context ) ;
if ( ! concurrent )
{
/* Close the heap and we're done, in the non-concurrent case */
@ -3524,6 +3576,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
Oid newIndexId ;
Relation indexRel ;
Relation heapRel ;
Oid save_userid ;
int save_sec_context ;
int save_nestlevel ;
Relation newIndexRel ;
LockRelId * lockrelid ;
Oid tablespaceid ;
@ -3532,6 +3587,16 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
heapRel = table_open ( indexRel - > rd_index - > indrelid ,
ShareUpdateExclusiveLock ) ;
/*
* Switch to the table owner ' s userid , so that any index functions are
* run as that user . Also lock down security - restricted operations
* and arrange to make GUC variable changes local to this command .
*/
GetUserIdAndSecContext ( & save_userid , & save_sec_context ) ;
SetUserIdAndSecContext ( heapRel - > rd_rel - > relowner ,
save_sec_context | SECURITY_RESTRICTED_OPERATION ) ;
save_nestlevel = NewGUCNestLevel ( ) ;
/* determine safety of this index for set_indexsafe_procflags */
idx - > safe = ( indexRel - > rd_indexprs = = NIL & &
indexRel - > rd_indpred = = NIL ) ;
@ -3607,6 +3672,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
index_close ( indexRel , NoLock ) ;
index_close ( newIndexRel , NoLock ) ;
/* Roll back any GUC changes executed by index functions */
AtEOXact_GUC ( false , save_nestlevel ) ;
/* Restore userid and security context */
SetUserIdAndSecContext ( save_userid , save_sec_context ) ;
table_close ( heapRel , NoLock ) ;
}