diff options
Diffstat (limited to 'src/backend/commands/extension.c')
-rw-r--r-- | src/backend/commands/extension.c | 81 |
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; |