From d89494166351e1fdac77d87c6af500401deb2422 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 3 Nov 2015 18:42:02 -0500 Subject: Allow postgres_fdw to ship extension funcs/operators for remote execution. The user can whitelist specified extension(s) in the foreign server's options, whereupon we will treat immutable functions and operators of those extensions as candidates to be sent for remote execution. Whitelisting an extension in this way basically promises that the extension exists on the remote server and behaves compatibly with the local instance. We have no way to prove that formally, so we have to rely on the user to get it right. But this seems like something that people can usually get right in practice. We might in future allow functions and operators to be whitelisted individually, but extension granularity is a very convenient special case, so it got done first. The patch as-committed lacks any regression tests, which is unfortunate, but introducing dependencies on other extensions for testing purposes would break "make installcheck" scenarios, which is worse. I have some ideas about klugy ways around that, but it seems like material for a separate patch. For the moment, leave the problem open. Paul Ramsey, hacked up a bit more by me --- contrib/postgres_fdw/option.c | 54 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'contrib/postgres_fdw/option.c') diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c index 7547ec28172..380ac80ab3a 100644 --- a/contrib/postgres_fdw/option.c +++ b/contrib/postgres_fdw/option.c @@ -19,6 +19,8 @@ #include "catalog/pg_foreign_table.h" #include "catalog/pg_user_mapping.h" #include "commands/defrem.h" +#include "commands/extension.h" +#include "utils/builtins.h" /* @@ -124,6 +126,11 @@ postgres_fdw_validator(PG_FUNCTION_ARGS) errmsg("%s requires a non-negative numeric value", def->defname))); } + else if (strcmp(def->defname, "extensions") == 0) + { + /* check list syntax, warn about uninstalled extensions */ + (void) ExtractExtensionList(defGetString(def), true); + } } PG_RETURN_VOID(); @@ -150,6 +157,8 @@ InitPgFdwOptions(void) /* cost factors */ {"fdw_startup_cost", ForeignServerRelationId, false}, {"fdw_tuple_cost", ForeignServerRelationId, false}, + /* shippable extensions */ + {"extensions", ForeignServerRelationId, false}, /* updatable is available on both server and table */ {"updatable", ForeignServerRelationId, false}, {"updatable", ForeignTableRelationId, false}, @@ -293,3 +302,48 @@ ExtractConnectionOptions(List *defelems, const char **keywords, } return i; } + +/* + * Parse a comma-separated string and return a List of the OIDs of the + * extensions named in the string. If any names in the list cannot be + * found, report a warning if warnOnMissing is true, else just silently + * ignore them. + */ +List * +ExtractExtensionList(const char *extensionsString, bool warnOnMissing) +{ + List *extensionOids = NIL; + List *extlist; + ListCell *lc; + + /* SplitIdentifierString scribbles on its input, so pstrdup first */ + if (!SplitIdentifierString(pstrdup(extensionsString), ',', &extlist)) + { + /* syntax error in name list */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" must be a list of extension names", + "extensions"))); + } + + foreach(lc, extlist) + { + const char *extension_name = (const char *) lfirst(lc); + Oid extension_oid = get_extension_oid(extension_name, true); + + if (OidIsValid(extension_oid)) + { + extensionOids = lappend_oid(extensionOids, extension_oid); + } + else if (warnOnMissing) + { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("extension \"%s\" is not installed", + extension_name))); + } + } + + list_free(extlist); + return extensionOids; +} -- cgit v1.2.3