@@ -9379,28 +9379,35 @@ ATExecGenericOptions(Relation rel, List *options)
9379
9379
heap_freetuple (tuple );
9380
9380
}
9381
9381
9382
-
9383
9382
/*
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.
9387
9384
*/
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 )
9391
9388
{
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 );
9397
9397
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 );
9399
9401
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 )));
9402
9408
9403
9409
/* Check relation type against type specified in the ALTER command */
9410
+ stmttype = * (ObjectType * ) arg ;
9404
9411
switch (stmttype )
9405
9412
{
9406
9413
case OBJECT_TABLE :
@@ -9412,61 +9419,43 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
9412
9419
break ;
9413
9420
9414
9421
case OBJECT_SEQUENCE :
9415
- if (rel -> rd_rel -> relkind != RELKIND_SEQUENCE )
9422
+ if (form -> relkind != RELKIND_SEQUENCE )
9416
9423
ereport (ERROR ,
9417
9424
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9418
- errmsg ("\"%s\" is not a sequence" ,
9419
- RelationGetRelationName (rel ))));
9425
+ errmsg ("\"%s\" is not a sequence" , rv -> relname )));
9420
9426
break ;
9421
9427
9422
9428
case OBJECT_VIEW :
9423
- if (rel -> rd_rel -> relkind != RELKIND_VIEW )
9429
+ if (form -> relkind != RELKIND_VIEW )
9424
9430
ereport (ERROR ,
9425
9431
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9426
- errmsg ("\"%s\" is not a view" ,
9427
- RelationGetRelationName (rel ))));
9432
+ errmsg ("\"%s\" is not a view" , rv -> relname )));
9428
9433
break ;
9429
9434
9430
9435
case OBJECT_FOREIGN_TABLE :
9431
- if (rel -> rd_rel -> relkind != RELKIND_FOREIGN_TABLE )
9436
+ if (form -> relkind != RELKIND_FOREIGN_TABLE )
9432
9437
ereport (ERROR ,
9433
9438
(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 )));
9436
9440
break ;
9437
9441
9438
9442
default :
9439
9443
elog (ERROR , "unrecognized object type: %d" , (int ) stmttype );
9440
9444
}
9441
9445
9442
9446
/* Can we change the schema of this tuple? */
9443
- switch (rel -> rd_rel -> relkind )
9447
+ switch (form -> relkind )
9444
9448
{
9445
9449
case RELKIND_RELATION :
9446
9450
case RELKIND_VIEW :
9451
+ case RELKIND_SEQUENCE :
9447
9452
case RELKIND_FOREIGN_TABLE :
9448
9453
/* ok to change schema */
9449
9454
break ;
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 ;
9465
9455
case RELKIND_COMPOSITE_TYPE :
9466
9456
ereport (ERROR ,
9467
9457
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9468
- errmsg ("\"%s\" is a composite type" ,
9469
- RelationGetRelationName (rel )),
9458
+ errmsg ("\"%s\" is a composite type" , rv -> relname ),
9470
9459
errhint ("Use ALTER TYPE instead." )));
9471
9460
break ;
9472
9461
case RELKIND_INDEX :
@@ -9476,7 +9465,45 @@ AlterTableNamespace(RangeVar *relation, const char *newschema,
9476
9465
ereport (ERROR ,
9477
9466
(errcode (ERRCODE_WRONG_OBJECT_TYPE ),
9478
9467
errmsg ("\"%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 ))));
9480
9507
}
9481
9508
9482
9509
/* get schema OID and check its permissions */
0 commit comments