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

Commit 01467d3

Browse files
committed
Extend "ALTER EXTENSION ADD object" to permit "DROP object" as well.
Per discussion, this is something we should have sooner rather than later, and it doesn't take much additional code to support it.
1 parent 289d730 commit 01467d3

File tree

12 files changed

+207
-112
lines changed

12 files changed

+207
-112
lines changed

doc/src/sgml/ref/alter_extension.sgml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ PostgreSQL documentation
2525
<synopsis>
2626
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
2727
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <replaceable class="PARAMETER">member_object</replaceable>
28+
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP <replaceable class="PARAMETER">member_object</replaceable>
2829

2930
<phrase>where <replaceable class="PARAMETER">member_object</replaceable> is:</phrase>
3031

@@ -82,6 +83,17 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD
8283
</para>
8384
</listitem>
8485
</varlistentry>
86+
87+
<varlistentry>
88+
<term><literal>DROP <replaceable class="PARAMETER">member_object</replaceable></literal></term>
89+
<listitem>
90+
<para>
91+
This form removes a member object from the extension. This is mainly
92+
useful in extension upgrade scripts. The object is not dropped, only
93+
disassociated from the extension.
94+
</para>
95+
</listitem>
96+
</varlistentry>
8597
</variablelist>
8698

8799
See <xref linkend="extend-extensions"> for more information about these
@@ -123,7 +135,8 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD
123135
<term><replaceable class="parameter">operator_name</replaceable></term>
124136
<listitem>
125137
<para>
126-
The name of an object to be added to the extension. Names of tables,
138+
The name of an object to be added to or removed from the extension.
139+
Names of tables,
127140
aggregates, domains, foreign tables, functions, operators,
128141
operator classes, operator families, sequences, text search objects,
129142
types, and views can be schema-qualified.

src/backend/catalog/pg_depend.c

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,57 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId,
199199
return count;
200200
}
201201

202+
/*
203+
* deleteDependencyRecordsForClass -- delete all records with given depender
204+
* classId/objectId, dependee classId, and deptype.
205+
* Returns the number of records deleted.
206+
*
207+
* This is a variant of deleteDependencyRecordsFor, useful when revoking
208+
* an object property that is expressed by a dependency record (such as
209+
* extension membership).
210+
*/
211+
long
212+
deleteDependencyRecordsForClass(Oid classId, Oid objectId,
213+
Oid refclassId, char deptype)
214+
{
215+
long count = 0;
216+
Relation depRel;
217+
ScanKeyData key[2];
218+
SysScanDesc scan;
219+
HeapTuple tup;
220+
221+
depRel = heap_open(DependRelationId, RowExclusiveLock);
222+
223+
ScanKeyInit(&key[0],
224+
Anum_pg_depend_classid,
225+
BTEqualStrategyNumber, F_OIDEQ,
226+
ObjectIdGetDatum(classId));
227+
ScanKeyInit(&key[1],
228+
Anum_pg_depend_objid,
229+
BTEqualStrategyNumber, F_OIDEQ,
230+
ObjectIdGetDatum(objectId));
231+
232+
scan = systable_beginscan(depRel, DependDependerIndexId, true,
233+
SnapshotNow, 2, key);
234+
235+
while (HeapTupleIsValid(tup = systable_getnext(scan)))
236+
{
237+
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
238+
239+
if (depform->refclassid == refclassId && depform->deptype == deptype)
240+
{
241+
simple_heap_delete(depRel, &tup->t_self);
242+
count++;
243+
}
244+
}
245+
246+
systable_endscan(scan);
247+
248+
heap_close(depRel, RowExclusiveLock);
249+
250+
return count;
251+
}
252+
202253
/*
203254
* Adjust dependency record(s) to point to a different object of the same type
204255
*
@@ -470,39 +521,8 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
470521
void
471522
markSequenceUnowned(Oid seqId)
472523
{
473-
Relation depRel;
474-
ScanKeyData key[2];
475-
SysScanDesc scan;
476-
HeapTuple tup;
477-
478-
depRel = heap_open(DependRelationId, RowExclusiveLock);
479-
480-
ScanKeyInit(&key[0],
481-
Anum_pg_depend_classid,
482-
BTEqualStrategyNumber, F_OIDEQ,
483-
ObjectIdGetDatum(RelationRelationId));
484-
ScanKeyInit(&key[1],
485-
Anum_pg_depend_objid,
486-
BTEqualStrategyNumber, F_OIDEQ,
487-
ObjectIdGetDatum(seqId));
488-
489-
scan = systable_beginscan(depRel, DependDependerIndexId, true,
490-
SnapshotNow, 2, key);
491-
492-
while (HeapTupleIsValid((tup = systable_getnext(scan))))
493-
{
494-
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
495-
496-
if (depform->refclassid == RelationRelationId &&
497-
depform->deptype == DEPENDENCY_AUTO)
498-
{
499-
simple_heap_delete(depRel, &tup->t_self);
500-
}
501-
}
502-
503-
systable_endscan(scan);
504-
505-
heap_close(depRel, RowExclusiveLock);
524+
deleteDependencyRecordsForClass(RelationRelationId, seqId,
525+
RelationRelationId, DEPENDENCY_AUTO);
506526
}
507527

508528
/*

src/backend/commands/extension.c

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,14 +1436,15 @@ AlterExtensionNamespace(List *names, const char *newschema)
14361436
}
14371437

14381438
/*
1439-
* Execute ALTER EXTENSION ADD
1439+
* Execute ALTER EXTENSION ADD/DROP
14401440
*/
14411441
void
1442-
ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
1442+
ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
14431443
{
14441444
ObjectAddress extension;
14451445
ObjectAddress object;
14461446
Relation relation;
1447+
Oid oldExtension;
14471448

14481449
/*
14491450
* For now, insist on superuser privilege. Later we might want to
@@ -1462,25 +1463,54 @@ ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
14621463
/*
14631464
* Translate the parser representation that identifies the object into
14641465
* an ObjectAddress. get_object_address() will throw an error if the
1465-
* object does not exist, and will also acquire a lock on the object
1466-
* to guard against concurrent DROP and ALTER EXTENSION ADD operations.
1466+
* object does not exist, and will also acquire a lock on the object to
1467+
* guard against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
14671468
*/
14681469
object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
14691470
&relation, ShareUpdateExclusiveLock);
14701471

14711472
/*
1472-
* Complain if object is already attached to some extension.
1473+
* Check existing extension membership.
14731474
*/
1474-
if (getExtensionOfObject(object.classId, object.objectId) != InvalidOid)
1475-
ereport(ERROR,
1476-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1477-
errmsg("%s is already a member of an extension",
1478-
getObjectDescription(&object))));
1475+
oldExtension = getExtensionOfObject(object.classId, object.objectId);
14791476

1480-
/*
1481-
* OK, add the dependency.
1482-
*/
1483-
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
1477+
if (stmt->action > 0)
1478+
{
1479+
/*
1480+
* ADD, so complain if object is already attached to some extension.
1481+
*/
1482+
if (OidIsValid(oldExtension))
1483+
ereport(ERROR,
1484+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1485+
errmsg("%s is already a member of extension \"%s\"",
1486+
getObjectDescription(&object),
1487+
get_extension_name(oldExtension))));
1488+
1489+
/*
1490+
* OK, add the dependency.
1491+
*/
1492+
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
1493+
}
1494+
else
1495+
{
1496+
/*
1497+
* DROP, so complain if it's not a member.
1498+
*/
1499+
if (oldExtension != extension.objectId)
1500+
ereport(ERROR,
1501+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1502+
errmsg("%s is not a member of extension \"%s\"",
1503+
getObjectDescription(&object),
1504+
stmt->extname)));
1505+
1506+
/*
1507+
* OK, drop the dependency.
1508+
*/
1509+
if (deleteDependencyRecordsForClass(object.classId, object.objectId,
1510+
ExtensionRelationId,
1511+
DEPENDENCY_EXTENSION) != 1)
1512+
elog(ERROR, "unexpected number of extension dependency records");
1513+
}
14841514

14851515
/*
14861516
* If get_object_address() opened the relation for us, we close it to keep

src/backend/nodes/copyfuncs.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3251,12 +3251,13 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from)
32513251
return newnode;
32523252
}
32533253

3254-
static AlterExtensionAddStmt *
3255-
_copyAlterExtensionAddStmt(AlterExtensionAddStmt *from)
3254+
static AlterExtensionContentsStmt *
3255+
_copyAlterExtensionContentsStmt(AlterExtensionContentsStmt *from)
32563256
{
3257-
AlterExtensionAddStmt *newnode = makeNode(AlterExtensionAddStmt);
3257+
AlterExtensionContentsStmt *newnode = makeNode(AlterExtensionContentsStmt);
32583258

32593259
COPY_STRING_FIELD(extname);
3260+
COPY_SCALAR_FIELD(action);
32603261
COPY_SCALAR_FIELD(objtype);
32613262
COPY_NODE_FIELD(objname);
32623263
COPY_NODE_FIELD(objargs);
@@ -4266,8 +4267,8 @@ copyObject(void *from)
42664267
case T_CreateExtensionStmt:
42674268
retval = _copyCreateExtensionStmt(from);
42684269
break;
4269-
case T_AlterExtensionAddStmt:
4270-
retval = _copyAlterExtensionAddStmt(from);
4270+
case T_AlterExtensionContentsStmt:
4271+
retval = _copyAlterExtensionContentsStmt(from);
42714272
break;
42724273
case T_CreateFdwStmt:
42734274
retval = _copyCreateFdwStmt(from);

src/backend/nodes/equalfuncs.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,9 +1655,10 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
16551655
}
16561656

16571657
static bool
1658-
_equalAlterExtensionAddStmt(AlterExtensionAddStmt *a, AlterExtensionAddStmt *b)
1658+
_equalAlterExtensionContentsStmt(AlterExtensionContentsStmt *a, AlterExtensionContentsStmt *b)
16591659
{
16601660
COMPARE_STRING_FIELD(extname);
1661+
COMPARE_SCALAR_FIELD(action);
16611662
COMPARE_SCALAR_FIELD(objtype);
16621663
COMPARE_NODE_FIELD(objname);
16631664
COMPARE_NODE_FIELD(objargs);
@@ -2868,8 +2869,8 @@ equal(void *a, void *b)
28682869
case T_CreateExtensionStmt:
28692870
retval = _equalCreateExtensionStmt(a, b);
28702871
break;
2871-
case T_AlterExtensionAddStmt:
2872-
retval = _equalAlterExtensionAddStmt(a, b);
2872+
case T_AlterExtensionContentsStmt:
2873+
retval = _equalAlterExtensionContentsStmt(a, b);
28732874
break;
28742875
case T_CreateFdwStmt:
28752876
retval = _equalCreateFdwStmt(a, b);

0 commit comments

Comments
 (0)