@@ -9379,28 +9379,35 @@ ATExecGenericOptions(Relation rel, List *options)
93799379heap_freetuple (tuple );
93809380}
93819381
9382-
93839382/*
9384- * Execute ALTER TABLE SET SCHEMA
9385- *
9386- * Note: caller must have checked ownership of the relation already
9383+ * Perform permissions and integrity checks before acquiring a relation lock.
93879384 */
9388- void
9389- AlterTableNamespace ( RangeVar * relation , const char * newschema ,
9390- ObjectType stmttype , LOCKMODE lockmode )
9385+ static void
9386+ RangeVarCallbackForAlterTableNamespace ( const RangeVar * rv , Oid relid ,
9387+ Oid oldrelid , void * arg )
93919388{
9392- Relation rel ;
9393- Oid relid ;
9394- Oid oldNspOid ;
9395- Oid nspOid ;
9396- Relation classRel ;
9389+ HeapTuple tuple ;
9390+ Form_pg_class form ;
9391+ ObjectType stmttype ;
9392+
9393+ tuple = SearchSysCache1 (RELOID ,ObjectIdGetDatum (relid ));
9394+ if (!HeapTupleIsValid (tuple ))
9395+ return ;/* concurrently dropped */
9396+ form = (Form_pg_class )GETSTRUCT (tuple );
93979397
9398- rel = relation_openrv (relation ,lockmode );
9398+ /* Must own table. */
9399+ if (!pg_class_ownercheck (relid ,GetUserId ()))
9400+ aclcheck_error (ACLCHECK_NOT_OWNER ,ACL_KIND_CLASS ,rv -> relname );
93999401
9400- relid = RelationGetRelid (rel );
9401- oldNspOid = RelationGetNamespace (rel );
9402+ /* No system table modifications unless explicitly allowed. */
9403+ if (!allowSystemTableMods && IsSystemClass (form ))
9404+ ereport (ERROR ,
9405+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
9406+ errmsg ("permission denied: \"%s\" is a system catalog" ,
9407+ rv -> relname )));
94029408
94039409/* Check relation type against type specified in the ALTER command */
9410+ stmttype = * (ObjectType * )arg ;
94049411switch (stmttype )
94059412{
94069413case OBJECT_TABLE :
@@ -9412,61 +9419,43 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
94129419break ;
94139420
94149421case OBJECT_SEQUENCE :
9415- if (rel -> rd_rel -> relkind != RELKIND_SEQUENCE )
9422+ if (form -> relkind != RELKIND_SEQUENCE )
94169423ereport (ERROR ,
94179424(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9418- errmsg ("\"%s\" is not a sequence" ,
9419- RelationGetRelationName (rel ))));
9425+ errmsg ("\"%s\" is not a sequence" ,rv -> relname )));
94209426break ;
94219427
94229428case OBJECT_VIEW :
9423- if (rel -> rd_rel -> relkind != RELKIND_VIEW )
9429+ if (form -> relkind != RELKIND_VIEW )
94249430ereport (ERROR ,
94259431(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9426- errmsg ("\"%s\" is not a view" ,
9427- RelationGetRelationName (rel ))));
9432+ errmsg ("\"%s\" is not a view" ,rv -> relname )));
94289433break ;
94299434
94309435case OBJECT_FOREIGN_TABLE :
9431- if (rel -> rd_rel -> relkind != RELKIND_FOREIGN_TABLE )
9436+ if (form -> relkind != RELKIND_FOREIGN_TABLE )
94329437ereport (ERROR ,
94339438(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9434- errmsg ("\"%s\" is not a foreign table" ,
9435- RelationGetRelationName (rel ))));
9439+ errmsg ("\"%s\" is not a foreign table" ,rv -> relname )));
94369440break ;
94379441
94389442default :
94399443elog (ERROR ,"unrecognized object type: %d" , (int )stmttype );
94409444}
94419445
94429446/* Can we change the schema of this tuple? */
9443- switch (rel -> rd_rel -> relkind )
9447+ switch (form -> relkind )
94449448{
94459449case RELKIND_RELATION :
94469450case RELKIND_VIEW :
9451+ case RELKIND_SEQUENCE :
94479452case RELKIND_FOREIGN_TABLE :
94489453/* ok to change schema */
94499454break ;
9450- case RELKIND_SEQUENCE :
9451- {
9452- /* if it's an owned sequence, disallow moving it by itself */
9453- Oid tableId ;
9454- int32 colId ;
9455-
9456- if (sequenceIsOwned (relid ,& tableId ,& colId ))
9457- ereport (ERROR ,
9458- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
9459- errmsg ("cannot move an owned sequence into another schema" ),
9460- errdetail ("Sequence \"%s\" is linked to table \"%s\"." ,
9461- RelationGetRelationName (rel ),
9462- get_rel_name (tableId ))));
9463- }
9464- break ;
94659455case RELKIND_COMPOSITE_TYPE :
94669456ereport (ERROR ,
94679457(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9468- errmsg ("\"%s\" is a composite type" ,
9469- RelationGetRelationName (rel )),
9458+ errmsg ("\"%s\" is a composite type" ,rv -> relname ),
94709459errhint ("Use ALTER TYPE instead." )));
94719460break ;
94729461case RELKIND_INDEX :
@@ -9476,7 +9465,45 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
94769465ereport (ERROR ,
94779466(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
94789467errmsg ("\"%s\" is not a table, view, sequence, or foreign table" ,
9479- RelationGetRelationName (rel ))));
9468+ rv -> relname )));
9469+ }
9470+
9471+ ReleaseSysCache (tuple );
9472+ }
9473+
9474+ /*
9475+ * Execute ALTER TABLE SET SCHEMA
9476+ */
9477+ void
9478+ AlterTableNamespace (RangeVar * relation ,const char * newschema ,
9479+ ObjectType stmttype ,LOCKMODE lockmode )
9480+ {
9481+ Relation rel ;
9482+ Oid relid ;
9483+ Oid oldNspOid ;
9484+ Oid nspOid ;
9485+ Relation classRel ;
9486+
9487+ relid = RangeVarGetRelidExtended (relation ,lockmode , false, false,
9488+ RangeVarCallbackForAlterTableNamespace ,
9489+ (void * )& stmttype );
9490+ rel = relation_open (relid ,NoLock );
9491+
9492+ oldNspOid = RelationGetNamespace (rel );
9493+
9494+ /* If it's an owned sequence, disallow moving it by itself. */
9495+ if (rel -> rd_rel -> relkind == RELKIND_SEQUENCE )
9496+ {
9497+ Oid tableId ;
9498+ int32 colId ;
9499+
9500+ if (sequenceIsOwned (relid ,& tableId ,& colId ))
9501+ ereport (ERROR ,
9502+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
9503+ errmsg ("cannot move an owned sequence into another schema" ),
9504+ errdetail ("Sequence \"%s\" is linked to table \"%s\"." ,
9505+ RelationGetRelationName (rel ),
9506+ get_rel_name (tableId ))));
94809507}
94819508
94829509/* get schema OID and check its permissions */