aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/extension.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-02-09 11:55:32 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2011-02-09 11:56:37 -0500
commit5bc178b89f3ab93fb3845a941769c212f5eeaf1a (patch)
tree30f60f6497e97bf4c792bd581a3296aff5a6c5e5 /src/backend/commands/extension.c
parent70802e0dbef0af4bf73ce25489b8be6e40eca2be (diff)
downloadpostgresql-5bc178b89f3ab93fb3845a941769c212f5eeaf1a.tar.gz
postgresql-5bc178b89f3ab93fb3845a941769c212f5eeaf1a.zip
Implement "ALTER EXTENSION ADD object".
This is an essential component of making the extension feature usable; first because it's needed in the process of converting an existing installation containing "loose" objects of an old contrib module into the extension-based world, and second because we'll have to use it in pg_dump --binary-upgrade, as per recent discussion. Loosely based on part of Dimitri Fontaine's ALTER EXTENSION UPGRADE patch.
Diffstat (limited to 'src/backend/commands/extension.c')
-rw-r--r--src/backend/commands/extension.c59
1 files changed, 58 insertions, 1 deletions
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index ee42d2e13df..41667fb3afc 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1134,7 +1134,7 @@ pg_extension_config_dump(PG_FUNCTION_ARGS)
if (getExtensionOfObject(RelationRelationId, tableoid) !=
CurrentExtensionObject)
ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("table \"%s\" is not a member of the extension being created",
tablename)));
@@ -1392,3 +1392,60 @@ AlterExtensionNamespace(List *names, const char *newschema)
changeDependencyFor(ExtensionRelationId, extensionOid,
NamespaceRelationId, oldNspOid, nspOid);
}
+
+/*
+ * Execute ALTER EXTENSION ADD
+ */
+void
+ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
+{
+ ObjectAddress extension;
+ ObjectAddress object;
+ Relation relation;
+
+ /*
+ * For now, insist on superuser privilege. Later we might want to
+ * relax this to ownership of the target object and the extension.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ (errmsg("must be superuser to use ALTER EXTENSION"))));
+
+ /* Do this next to fail on nonexistent extension */
+ extension.classId = ExtensionRelationId;
+ extension.objectId = get_extension_oid(stmt->extname, false);
+ extension.objectSubId = 0;
+
+ /*
+ * Translate the parser representation that identifies the object into
+ * an ObjectAddress. get_object_address() will throw an error if the
+ * object does not exist, and will also acquire a lock on the object
+ * to guard against concurrent DROP and ALTER EXTENSION ADD operations.
+ */
+ object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
+ &relation, ShareUpdateExclusiveLock);
+
+ /*
+ * Complain if object is already attached to some extension.
+ */
+ if (getExtensionOfObject(object.classId, object.objectId) != InvalidOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("%s is already a member of an extension",
+ getObjectDescription(&object))));
+
+ /*
+ * OK, add the dependency.
+ */
+ recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
+
+ /*
+ * If get_object_address() opened the relation for us, we close it to keep
+ * the reference count correct - but we retain any locks acquired by
+ * get_object_address() until commit time, to guard against concurrent
+ * activity.
+ */
+ if (relation != NULL)
+ relation_close(relation, NoLock);
+}