Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit04f28bd

Browse files
committed
Fix ALTER EXTENSION / SET SCHEMA
In its original conception, it was leaving some objects into the oldschema, but without their proper pg_depend entries; this meant that theold schema could be dropped, causing future pg_dump calls to fail on theaffected database. This was originally reported by Jeff Frost as #6704;there have been other complaints elsewhere that can probably be tracedto this bug.To fix, be more consistent about altering a table's subsidiary objectsalong the table itself; this requires some restructuring in how tablesare relocated when altering an extension -- hence the newAlterTableNamespaceInternal routine which encapsulates it for both theALTER TABLE and the ALTER EXTENSION cases.There was another bug lurking here, which was unmasked after fixing theprevious one: certain objects would be reached twice via the dependencygraph, and the second attempt to move them would cause the entireoperation to fail. Per discussion, it seems the best fix for this is todo more careful tracking of objects already moved: we now maintain alist of moved objects, to avoid attempting to do it twice for the sameobject.Authors: Alvaro Herrera, Dimitri FontaineReviewed by Tom Lane
1 parent4af3dda commit04f28bd

File tree

9 files changed

+148
-67
lines changed

9 files changed

+148
-67
lines changed

‎src/backend/catalog/pg_constraint.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,7 @@ RenameConstraintById(Oid conId, const char *newname)
679679
*/
680680
void
681681
AlterConstraintNamespaces(OidownerId,OidoldNspId,
682-
OidnewNspId,boolisType)
682+
OidnewNspId,boolisType,ObjectAddresses*objsMoved)
683683
{
684684
RelationconRel;
685685
ScanKeyDatakey[1];
@@ -712,6 +712,14 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
712712
while (HeapTupleIsValid((tup=systable_getnext(scan))))
713713
{
714714
Form_pg_constraintconform= (Form_pg_constraint)GETSTRUCT(tup);
715+
ObjectAddressthisobj;
716+
717+
thisobj.classId=ConstraintRelationId;
718+
thisobj.objectId=HeapTupleGetOid(tup);
719+
thisobj.objectSubId=0;
720+
721+
if (object_address_present(&thisobj,objsMoved))
722+
continue;
715723

716724
if (conform->connamespace==oldNspId)
717725
{
@@ -729,6 +737,8 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
729737
* changeDependencyFor().
730738
*/
731739
}
740+
741+
add_exact_object_address(&thisobj,objsMoved);
732742
}
733743

734744
systable_endscan(scan);

‎src/backend/commands/alter.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,8 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
252252
* object doesn't have a schema.
253253
*/
254254
Oid
255-
AlterObjectNamespace_oid(OidclassId,Oidobjid,OidnspOid)
255+
AlterObjectNamespace_oid(OidclassId,Oidobjid,OidnspOid,
256+
ObjectAddresses*objsMoved)
256257
{
257258
OidoldNspOid=InvalidOid;
258259
ObjectAddressdep;
@@ -266,20 +267,11 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid)
266267
caseOCLASS_CLASS:
267268
{
268269
Relationrel;
269-
RelationclassRel;
270270

271271
rel=relation_open(objid,AccessExclusiveLock);
272272
oldNspOid=RelationGetNamespace(rel);
273273

274-
classRel=heap_open(RelationRelationId,RowExclusiveLock);
275-
276-
AlterRelationNamespaceInternal(classRel,
277-
objid,
278-
oldNspOid,
279-
nspOid,
280-
true);
281-
282-
heap_close(classRel,RowExclusiveLock);
274+
AlterTableNamespaceInternal(rel,oldNspOid,nspOid,objsMoved);
283275

284276
relation_close(rel,NoLock);
285277
break;
@@ -290,7 +282,7 @@ AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid)
290282
break;
291283

292284
caseOCLASS_TYPE:
293-
oldNspOid=AlterTypeNamespace_oid(objid,nspOid);
285+
oldNspOid=AlterTypeNamespace_oid(objid,nspOid,objsMoved);
294286
break;
295287

296288
caseOCLASS_COLLATION:

‎src/backend/commands/extension.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2204,6 +2204,7 @@ AlterExtensionNamespace(List *names, const char *newschema)
22042204
RelationdepRel;
22052205
SysScanDescdepScan;
22062206
HeapTupledepTup;
2207+
ObjectAddresses*objsMoved;
22072208

22082209
if (list_length(names)!=1)
22092210
ereport(ERROR,
@@ -2278,6 +2279,8 @@ AlterExtensionNamespace(List *names, const char *newschema)
22782279
errmsg("extension \"%s\" does not support SET SCHEMA",
22792280
NameStr(extForm->extname))));
22802281

2282+
objsMoved=new_object_addresses();
2283+
22812284
/*
22822285
* Scan pg_depend to find objects that depend directly on the extension,
22832286
* and alter each one's schema.
@@ -2317,9 +2320,11 @@ AlterExtensionNamespace(List *names, const char *newschema)
23172320
if (dep.objectSubId!=0)/* should not happen */
23182321
elog(ERROR,"extension should not have a sub-object dependency");
23192322

2323+
/* Relocate the object */
23202324
dep_oldNspOid=AlterObjectNamespace_oid(dep.classId,
23212325
dep.objectId,
2322-
nspOid);
2326+
nspOid,
2327+
objsMoved);
23232328

23242329
/*
23252330
* Remember previous namespace of first object that has one

‎src/backend/commands/tablecmds.c

Lines changed: 85 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,10 @@ static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
261261
int16seqNumber,RelationinhRelation);
262262
staticintfindAttrByName(constchar*attributeName,List*schema);
263263
staticvoidAlterIndexNamespaces(RelationclassRel,Relationrel,
264-
OidoldNspOid,OidnewNspOid);
264+
OidoldNspOid,OidnewNspOid,ObjectAddresses*objsMoved);
265265
staticvoidAlterSeqNamespaces(RelationclassRel,Relationrel,
266-
OidoldNspOid,OidnewNspOid,
267-
constchar*newNspName,LOCKMODElockmode);
266+
OidoldNspOid,OidnewNspOid,ObjectAddresses*objsMoved,
267+
LOCKMODElockmode);
268268
staticvoidATExecValidateConstraint(Relationrel,char*constrName,
269269
boolrecurse,boolrecursing,LOCKMODElockmode);
270270
staticinttransformColumnNameList(OidrelId,List*colList,
@@ -9711,8 +9711,8 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt)
97119711
Oidrelid;
97129712
OidoldNspOid;
97139713
OidnspOid;
9714-
RelationclassRel;
97159714
RangeVar*newrv;
9715+
ObjectAddresses*objsMoved;
97169716

97179717
relid=RangeVarGetRelidExtended(stmt->relation,AccessExclusiveLock,
97189718
stmt->missing_ok, false,
@@ -9753,27 +9753,47 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt)
97539753
/* common checks on switching namespaces */
97549754
CheckSetNamespace(oldNspOid,nspOid,RelationRelationId,relid);
97559755

9756+
objsMoved=new_object_addresses();
9757+
AlterTableNamespaceInternal(rel,oldNspOid,nspOid,objsMoved);
9758+
free_object_addresses(objsMoved);
9759+
9760+
/* close rel, but keep lock until commit */
9761+
relation_close(rel,NoLock);
9762+
}
9763+
9764+
/*
9765+
* The guts of relocating a table to another namespace: besides moving
9766+
* the table itself, its dependent objects are relocated to the new schema.
9767+
*/
9768+
void
9769+
AlterTableNamespaceInternal(Relationrel,OidoldNspOid,OidnspOid,
9770+
ObjectAddresses*objsMoved)
9771+
{
9772+
RelationclassRel;
9773+
9774+
Assert(objsMoved!=NULL);
9775+
97569776
/* OK, modify the pg_class row and pg_depend entry */
97579777
classRel=heap_open(RelationRelationId,RowExclusiveLock);
97589778

9759-
AlterRelationNamespaceInternal(classRel,relid,oldNspOid,nspOid, true);
9779+
AlterRelationNamespaceInternal(classRel,RelationGetRelid(rel),oldNspOid,
9780+
nspOid, true,objsMoved);
97609781

97619782
/* Fix the table's row type too */
9762-
AlterTypeNamespaceInternal(rel->rd_rel->reltype,nspOid, false, false);
9783+
AlterTypeNamespaceInternal(rel->rd_rel->reltype,
9784+
nspOid, false, false,objsMoved);
97639785

97649786
/* Fix other dependent stuff */
97659787
if (rel->rd_rel->relkind==RELKIND_RELATION)
97669788
{
9767-
AlterIndexNamespaces(classRel,rel,oldNspOid,nspOid);
9768-
AlterSeqNamespaces(classRel,rel,oldNspOid,nspOid,stmt->newschema,
9769-
AccessExclusiveLock);
9770-
AlterConstraintNamespaces(relid,oldNspOid,nspOid, false);
9789+
AlterIndexNamespaces(classRel,rel,oldNspOid,nspOid,objsMoved);
9790+
AlterSeqNamespaces(classRel,rel,oldNspOid,nspOid,
9791+
objsMoved,AccessExclusiveLock);
9792+
AlterConstraintNamespaces(RelationGetRelid(rel),oldNspOid,nspOid,
9793+
false,objsMoved);
97719794
}
97729795

97739796
heap_close(classRel,RowExclusiveLock);
9774-
9775-
/* close rel, but keep lock until commit */
9776-
relation_close(rel,NoLock);
97779797
}
97789798

97799799
/*
@@ -9784,10 +9804,11 @@ AlterTableNamespace(AlterObjectSchemaStmt *stmt)
97849804
void
97859805
AlterRelationNamespaceInternal(RelationclassRel,OidrelOid,
97869806
OidoldNspOid,OidnewNspOid,
9787-
boolhasDependEntry)
9807+
boolhasDependEntry,ObjectAddresses*objsMoved)
97889808
{
97899809
HeapTupleclassTup;
97909810
Form_pg_classclassForm;
9811+
ObjectAddressthisobj;
97919812

97929813
classTup=SearchSysCacheCopy1(RELOID,ObjectIdGetDatum(relOid));
97939814
if (!HeapTupleIsValid(classTup))
@@ -9796,27 +9817,39 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
97969817

97979818
Assert(classForm->relnamespace==oldNspOid);
97989819

9799-
/* check for duplicate name (more friendly than unique-index failure) */
9800-
if (get_relname_relid(NameStr(classForm->relname),
9801-
newNspOid)!=InvalidOid)
9802-
ereport(ERROR,
9803-
(errcode(ERRCODE_DUPLICATE_TABLE),
9804-
errmsg("relation \"%s\" already exists in schema \"%s\"",
9805-
NameStr(classForm->relname),
9806-
get_namespace_name(newNspOid))));
9820+
thisobj.classId=RelationRelationId;
9821+
thisobj.objectId=relOid;
9822+
thisobj.objectSubId=0;
9823+
9824+
/*
9825+
* Do nothing when there's nothing to do.
9826+
*/
9827+
if (!object_address_present(&thisobj,objsMoved))
9828+
{
9829+
/* check for duplicate name (more friendly than unique-index failure) */
9830+
if (get_relname_relid(NameStr(classForm->relname),
9831+
newNspOid)!=InvalidOid)
9832+
ereport(ERROR,
9833+
(errcode(ERRCODE_DUPLICATE_TABLE),
9834+
errmsg("relation \"%s\" already exists in schema \"%s\"",
9835+
NameStr(classForm->relname),
9836+
get_namespace_name(newNspOid))));
98079837

9808-
/* classTup is a copy, so OK to scribble on */
9809-
classForm->relnamespace=newNspOid;
9838+
/* classTup is a copy, so OK to scribble on */
9839+
classForm->relnamespace=newNspOid;
98109840

9811-
simple_heap_update(classRel,&classTup->t_self,classTup);
9812-
CatalogUpdateIndexes(classRel,classTup);
9841+
simple_heap_update(classRel,&classTup->t_self,classTup);
9842+
CatalogUpdateIndexes(classRel,classTup);
98139843

9814-
/* Update dependency on schema if caller said so */
9815-
if (hasDependEntry&&
9816-
changeDependencyFor(RelationRelationId,relOid,
9817-
NamespaceRelationId,oldNspOid,newNspOid)!=1)
9818-
elog(ERROR,"failed to change schema dependency for relation \"%s\"",
9819-
NameStr(classForm->relname));
9844+
/* Update dependency on schema if caller said so */
9845+
if (hasDependEntry&&
9846+
changeDependencyFor(RelationRelationId,relOid,
9847+
NamespaceRelationId,oldNspOid,newNspOid)!=1)
9848+
elog(ERROR,"failed to change schema dependency for relation \"%s\"",
9849+
NameStr(classForm->relname));
9850+
9851+
add_exact_object_address(&thisobj,objsMoved);
9852+
}
98209853

98219854
heap_freetuple(classTup);
98229855
}
@@ -9829,7 +9862,7 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
98299862
*/
98309863
staticvoid
98319864
AlterIndexNamespaces(RelationclassRel,Relationrel,
9832-
OidoldNspOid,OidnewNspOid)
9865+
OidoldNspOid,OidnewNspOid,ObjectAddresses*objsMoved)
98339866
{
98349867
List*indexList;
98359868
ListCell*l;
@@ -9839,15 +9872,27 @@ AlterIndexNamespaces(Relation classRel, Relation rel,
98399872
foreach(l,indexList)
98409873
{
98419874
OidindexOid=lfirst_oid(l);
9875+
ObjectAddressthisobj;
9876+
9877+
thisobj.classId=RelationRelationId;
9878+
thisobj.objectId=indexOid;
9879+
thisobj.objectSubId=0;
98429880

98439881
/*
98449882
* Note: currently, the index will not have its own dependency on the
98459883
* namespace, so we don't need to do changeDependencyFor(). There's no
98469884
* row type in pg_type, either.
9885+
*
9886+
* XXX this objsMoved test may be pointless -- surely we have a single
9887+
* dependency link from a relation to each index?
98479888
*/
9848-
AlterRelationNamespaceInternal(classRel,indexOid,
9849-
oldNspOid,newNspOid,
9850-
false);
9889+
if (!object_address_present(&thisobj,objsMoved))
9890+
{
9891+
AlterRelationNamespaceInternal(classRel,indexOid,
9892+
oldNspOid,newNspOid,
9893+
false,objsMoved);
9894+
add_exact_object_address(&thisobj,objsMoved);
9895+
}
98519896
}
98529897

98539898
list_free(indexList);
@@ -9862,7 +9907,8 @@ AlterIndexNamespaces(Relation classRel, Relation rel,
98629907
*/
98639908
staticvoid
98649909
AlterSeqNamespaces(RelationclassRel,Relationrel,
9865-
OidoldNspOid,OidnewNspOid,constchar*newNspName,LOCKMODElockmode)
9910+
OidoldNspOid,OidnewNspOid,ObjectAddresses*objsMoved,
9911+
LOCKMODElockmode)
98669912
{
98679913
RelationdepRel;
98689914
SysScanDescscan;
@@ -9914,14 +9960,14 @@ AlterSeqNamespaces(Relation classRel, Relation rel,
99149960
/* Fix the pg_class and pg_depend entries */
99159961
AlterRelationNamespaceInternal(classRel,depForm->objid,
99169962
oldNspOid,newNspOid,
9917-
true);
9963+
true,objsMoved);
99189964

99199965
/*
99209966
* Sequences have entries in pg_type. We need to be careful to move
99219967
* them to the new namespace, too.
99229968
*/
99239969
AlterTypeNamespaceInternal(RelationGetForm(seqRel)->reltype,
9924-
newNspOid, false, false);
9970+
newNspOid, false, false,objsMoved);
99259971

99269972
/* Now we can close it. Keep the lock till end of transaction. */
99279973
relation_close(seqRel,NoLock);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp