summaryrefslogtreecommitdiff
path: root/src/backend/commands/extension.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/extension.c')
-rw-r--r--src/backend/commands/extension.c81
1 files changed, 78 insertions, 3 deletions
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 02ff4a9a7fb..0eabe18335e 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -90,6 +90,8 @@ typedef struct ExtensionControlFile
bool trusted; /* allow becoming superuser on the fly? */
int encoding; /* encoding of the script file, or -1 */
List *requires; /* names of prerequisite extensions */
+ List *no_relocate; /* names of prerequisite extensions that
+ * should not be relocated */
} ExtensionControlFile;
/*
@@ -606,6 +608,21 @@ parse_extension_control_file(ExtensionControlFile *control,
item->name)));
}
}
+ else if (strcmp(item->name, "no_relocate") == 0)
+ {
+ /* Need a modifiable copy of string */
+ char *rawnames = pstrdup(item->value);
+
+ /* Parse string into list of identifiers */
+ if (!SplitIdentifierString(rawnames, ',', &control->no_relocate))
+ {
+ /* syntax error in name list */
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter \"%s\" must be a list of extension names",
+ item->name)));
+ }
+ }
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -845,6 +862,8 @@ extension_is_trusted(ExtensionControlFile *control)
* Execute the appropriate script file for installing or updating the extension
*
* If from_version isn't NULL, it's an update
+ *
+ * Note: requiredSchemas must be one-for-one with the control->requires list
*/
static void
execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
@@ -860,6 +879,7 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
int save_nestlevel;
StringInfoData pathbuf;
ListCell *lc;
+ ListCell *lc2;
/*
* Enforce superuser-ness if appropriate. We postpone these checks until
@@ -1031,6 +1051,27 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
}
/*
+ * Likewise, substitute required extensions' schema names for
+ * occurrences of @extschema:extension_name@.
+ */
+ Assert(list_length(control->requires) == list_length(requiredSchemas));
+ forboth(lc, control->requires, lc2, requiredSchemas)
+ {
+ char *reqextname = (char *) lfirst(lc);
+ Oid reqschema = lfirst_oid(lc2);
+ char *schemaName = get_namespace_name(reqschema);
+ const char *qSchemaName = quote_identifier(schemaName);
+ char *repltoken;
+
+ repltoken = psprintf("@extschema:%s@", reqextname);
+ t_sql = DirectFunctionCall3Coll(replace_text,
+ C_COLLATION_OID,
+ t_sql,
+ CStringGetTextDatum(repltoken),
+ CStringGetTextDatum(qSchemaName));
+ }
+
+ /*
* If module_pathname was set in the control file, substitute its
* value for occurrences of MODULE_PATHNAME.
*/
@@ -2817,9 +2858,43 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o
Oid dep_oldNspOid;
/*
- * Ignore non-membership dependencies. (Currently, the only other
- * case we could see here is a normal dependency from another
- * extension.)
+ * If a dependent extension has a no_relocate request for this
+ * extension, disallow SET SCHEMA. (XXX it's a bit ugly to do this in
+ * the same loop that's actually executing the renames: we may detect
+ * the error condition only after having expended a fair amount of
+ * work. However, the alternative is to do two scans of pg_depend,
+ * which seems like optimizing for failure cases. The rename work
+ * will all roll back cleanly enough if we do fail here.)
+ */
+ if (pg_depend->deptype == DEPENDENCY_NORMAL &&
+ pg_depend->classid == ExtensionRelationId)
+ {
+ char *depextname = get_extension_name(pg_depend->objid);
+ ExtensionControlFile *dcontrol;
+ ListCell *lc;
+
+ dcontrol = read_extension_control_file(depextname);
+ foreach(lc, dcontrol->no_relocate)
+ {
+ char *nrextname = (char *) lfirst(lc);
+
+ if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
+ NameStr(extForm->extname)),
+ errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
+ depextname,
+ NameStr(extForm->extname))));
+ }
+ }
+ }
+
+ /*
+ * Otherwise, ignore non-membership dependencies. (Currently, the
+ * only other case we could see here is a normal dependency from
+ * another extension.)
*/
if (pg_depend->deptype != DEPENDENCY_EXTENSION)
continue;