Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6b71c92

Browse files
committed
Prevent ALTER TYPE/DOMAIN/OPERATOR from changing extension membership.
If recordDependencyOnCurrentExtension is invoked on a pre-existing, free-standing object during an extension update script, that object will become owned by the extension. In our current code this is possible in three cases: * Replacing a "shell" type or operator. * CREATE OR REPLACE overwriting an existing object. * ALTER TYPE SET, ALTER DOMAIN SET, and ALTER OPERATOR SET. The first of these cases is intentional behavior, as noted by the existing comments for GenerateTypeDependencies. It seems like appropriate behavior for CREATE OR REPLACE too; at least, the obvious alternatives are not better. However, the fact that it happens during ALTER is an artifact of trying to share code (GenerateTypeDependencies and makeOperatorDependencies) between the CREATE and ALTER cases. Since an extension script would be unlikely to ALTER an object that didn't already belong to the extension, this behavior is not very troubling for the direct target object ... but ALTER TYPE SET will recurse to dependent domains, and it is very uncool for those to become owned by the extension if they were not already. Let's fix this by redefining the ALTER cases to never change extension membership, full stop. We could minimize the behavioral change by only changing the behavior when ALTER TYPE SET is recursing to a domain, but that would complicate the code and it does not seem like a better definition. Per bug #17144 from Alex Kozhemyakin. Back-patch to v13 where ALTER TYPE SET was added. (The other cases are older, but since they only affect the directly-named object, there's not enough of a problem to justify changing the behavior further back.) Discussion: https://postgr.es/m/17144-e67d7a8f049de9af@postgresql.org
1 parent b66336c commit 6b71c92

File tree

7 files changed

+41
-14
lines changed

7 files changed

+41
-14
lines changed

src/backend/catalog/pg_depend.c

+7
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,13 @@ recordMultipleDependencies(const ObjectAddress *depender,
179179
* existed), so we must check for a pre-existing extension membership entry.
180180
* Passing false is a guarantee that the object is newly created, and so
181181
* could not already be a member of any extension.
182+
*
183+
* Note: isReplace = true is typically used when updating a object in
184+
* CREATE OR REPLACE and similar commands. The net effect is that if an
185+
* extension script uses such a command on a pre-existing free-standing
186+
* object, the object will be absorbed into the extension. If the object
187+
* is already a member of some other extension, the command will fail.
188+
* This behavior is desirable for cases such as replacing a shell type.
182189
*/
183190
void
184191
recordDependencyOnCurrentExtension(const ObjectAddress *object,

src/backend/catalog/pg_operator.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ OperatorShellMake(const char *operatorName,
268268
CatalogTupleInsert(pg_operator_desc, tup);
269269

270270
/* Add dependencies for the entry */
271-
makeOperatorDependencies(tup, false);
271+
makeOperatorDependencies(tup, true, false);
272272

273273
heap_freetuple(tup);
274274

@@ -546,7 +546,7 @@ OperatorCreate(const char *operatorName,
546546
}
547547

548548
/* Add dependencies for the entry */
549-
address = makeOperatorDependencies(tup, isUpdate);
549+
address = makeOperatorDependencies(tup, true, isUpdate);
550550

551551
/* Post creation hook for new operator */
552552
InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
@@ -766,11 +766,17 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete)
766766
* complete operator, a new shell operator, a just-updated shell,
767767
* or an operator that's being modified by ALTER OPERATOR).
768768
*
769+
* makeExtensionDep should be true when making a new operator or
770+
* replacing a shell, false for ALTER OPERATOR. Passing false
771+
* will prevent any change in the operator's extension membership.
772+
*
769773
* NB: the OidIsValid tests in this routine are necessary, in case
770774
* the given operator is a shell.
771775
*/
772776
ObjectAddress
773-
makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
777+
makeOperatorDependencies(HeapTuple tuple,
778+
bool makeExtensionDep,
779+
bool isUpdate)
774780
{
775781
Form_pg_operator oper = (Form_pg_operator) GETSTRUCT(tuple);
776782
ObjectAddress myself,
@@ -857,7 +863,8 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate)
857863
oper->oprowner);
858864

859865
/* Dependency on extension */
860-
recordDependencyOnCurrentExtension(&myself, true);
866+
if (makeExtensionDep)
867+
recordDependencyOnCurrentExtension(&myself, true);
861868

862869
return myself;
863870
}

src/backend/catalog/pg_type.c

+16-8
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
167167
0,
168168
false,
169169
false,
170+
true, /* make extension dependency */
170171
false);
171172

172173
/* Post creation hook for new shell type */
@@ -504,6 +505,7 @@ TypeCreate(Oid newTypeOid,
504505
relationKind,
505506
isImplicitArray,
506507
isDependentType,
508+
true, /* make extension dependency */
507509
rebuildDeps);
508510

509511
/* Post creation hook for new type */
@@ -537,13 +539,17 @@ TypeCreate(Oid newTypeOid,
537539
* isDependentType is true if this is an implicit array or relation rowtype;
538540
* that means it doesn't need its own dependencies on owner etc.
539541
*
540-
* If rebuild is true, we remove existing dependencies and rebuild them
541-
* from scratch. This is needed for ALTER TYPE, and also when replacing
542-
* a shell type. We don't remove an existing extension dependency, though.
543-
* (That means an extension can't absorb a shell type created in another
544-
* extension, nor ALTER a type created by another extension. Also, if it
545-
* replaces a free-standing shell type or ALTERs a free-standing type,
546-
* that type will become a member of the extension.)
542+
* We make an extension-membership dependency if we're in an extension
543+
* script and makeExtensionDep is true (and isDependentType isn't true).
544+
* makeExtensionDep should be true when creating a new type or replacing a
545+
* shell type, but not for ALTER TYPE on an existing type. Passing false
546+
* causes the type's extension membership to be left alone.
547+
*
548+
* rebuild should be true if this is a pre-existing type. We will remove
549+
* existing dependencies and rebuild them from scratch. This is needed for
550+
* ALTER TYPE, and also when replacing a shell type. We don't remove any
551+
* existing extension dependency, though (hence, if makeExtensionDep is also
552+
* true and the type belongs to some other extension, an error will occur).
547553
*/
548554
void
549555
GenerateTypeDependencies(HeapTuple typeTuple,
@@ -553,6 +559,7 @@ GenerateTypeDependencies(HeapTuple typeTuple,
553559
char relationKind, /* only for relation rowtypes */
554560
bool isImplicitArray,
555561
bool isDependentType,
562+
bool makeExtensionDep,
556563
bool rebuild)
557564
{
558565
Form_pg_type typeForm = (Form_pg_type) GETSTRUCT(typeTuple);
@@ -611,7 +618,8 @@ GenerateTypeDependencies(HeapTuple typeTuple,
611618
recordDependencyOnNewAcl(TypeRelationId, typeObjectId, 0,
612619
typeForm->typowner, typacl);
613620

614-
recordDependencyOnCurrentExtension(&myself, rebuild);
621+
if (makeExtensionDep)
622+
recordDependencyOnCurrentExtension(&myself, rebuild);
615623
}
616624

617625
/* Normal dependencies on the I/O and support functions */

src/backend/commands/operatorcmds.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ AlterOperator(AlterOperatorStmt *stmt)
542542

543543
CatalogTupleUpdate(catalog, &tup->t_self, tup);
544544

545-
address = makeOperatorDependencies(tup, true);
545+
address = makeOperatorDependencies(tup, false, true);
546546

547547
InvokeObjectPostAlterHook(OperatorRelationId, oprId, 0);
548548

src/backend/commands/typecmds.c

+2
Original file line numberDiff line numberDiff line change
@@ -2675,6 +2675,7 @@ AlterDomainDefault(List *names, Node *defaultRaw)
26752675
0, /* relation kind is n/a */
26762676
false, /* a domain isn't an implicit array */
26772677
false, /* nor is it any kind of dependent type */
2678+
false, /* don't touch extension membership */
26782679
true); /* We do need to rebuild dependencies */
26792680

26802681
InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
@@ -4415,6 +4416,7 @@ AlterTypeRecurse(Oid typeOid, bool isImplicitArray,
44154416
0, /* we rejected composite types above */
44164417
isImplicitArray, /* it might be an array */
44174418
isImplicitArray, /* dependent iff it's array */
4419+
false, /* don't touch extension membership */
44184420
true);
44194421

44204422
InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);

src/include/catalog/pg_operator.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ extern ObjectAddress OperatorCreate(const char *operatorName,
9898
bool canMerge,
9999
bool canHash);
100100

101-
extern ObjectAddress makeOperatorDependencies(HeapTuple tuple, bool isUpdate);
101+
extern ObjectAddress makeOperatorDependencies(HeapTuple tuple,
102+
bool makeExtensionDep,
103+
bool isUpdate);
102104

103105
extern void OperatorUpd(Oid baseId, Oid commId, Oid negId, bool isDelete);
104106

src/include/catalog/pg_type.h

+1
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ extern void GenerateTypeDependencies(HeapTuple typeTuple,
386386
* rowtypes */
387387
bool isImplicitArray,
388388
bool isDependentType,
389+
bool makeExtensionDep,
389390
bool rebuild);
390391

391392
extern void RenameTypeInternal(Oid typeOid, const char *newTypeName,

0 commit comments

Comments
 (0)