From: Paul Ramsey Date: Tue, 18 Aug 2015 20:59:00 +0000 (+0000) Subject: #3238, handle case of "placeholder" GUC as well as real GUC conflicts X-Git-Tag: 2.2.0rc1~148 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=794aad0e3008be4872829afb261ff1a61ab23dc1;p=postgis #3238, handle case of "placeholder" GUC as well as real GUC conflicts git-svn-id: http://svn.osgeo.org/postgis/trunk@13937 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/postgis/lwgeom_backend_api.c b/postgis/lwgeom_backend_api.c index 5fbfa54af..9da26bf4d 100644 --- a/postgis/lwgeom_backend_api.c +++ b/postgis/lwgeom_backend_api.c @@ -102,6 +102,88 @@ static void lwgeom_backend_switch( const char* newvalue, void* extra ) lwpgerror("Can't find %s geometry backend", newvalue ); } + +#include "utils/guc.h" +#include "utils/guc_tables.h" + + +/* + * the bare comparison function for GUC names + */ +static int +guc_name_compare(const char *namea, const char *nameb) +{ + /* + * The temptation to use strcasecmp() here must be resisted, because the + * array ordering has to remain stable across setlocale() calls. So, build + * our own with a simple ASCII-only downcasing. + */ + while (*namea && *nameb) + { + char cha = *namea++; + char chb = *nameb++; + + if (cha >= 'A' && cha <= 'Z') + cha += 'a' - 'A'; + if (chb >= 'A' && chb <= 'Z') + chb += 'a' - 'A'; + if (cha != chb) + return cha - chb; + } + if (*namea) + return 1; /* a is longer */ + if (*nameb) + return -1; /* b is longer */ + return 0; +} + +/* + * comparator for qsorting and bsearching guc_variables array + */ +static int +guc_var_compare(const void *a, const void *b) +{ + const struct config_generic *confa = *(struct config_generic * const *) a; + const struct config_generic *confb = *(struct config_generic * const *) b; + + return guc_name_compare(confa->name, confb->name); +} + +/* +* This is copied from the top half of the find_option function +* in postgresql's guc.c. We search the guc_variables for our option. +* Then we make sure it's not a placeholder. Only then are we sure +* we have a potential conflict, of the sort experienced during an +* extension upgrade. +*/ +static int +guc_find_option(const char *name) +{ + const char **key = &name; + struct config_generic **res; + + /* + * By equating const char ** with struct config_generic *, we are assuming + * the name field is first in config_generic. + */ + res = (struct config_generic **) bsearch((void *) &key, + (void *) get_guc_variables(), + GetNumConfigOptions(), + sizeof(struct config_generic *), + guc_var_compare); + + /* Found nothing? Good */ + if ( ! res ) return 0; + + /* Hm, you found something, but maybe it's just a placeholder? */ + /* We'll consider a placehold a "not found" */ + if ( (*res)->flags & GUC_CUSTOM_PLACEHOLDER ) + return 0; + + return 1; +} + + void lwgeom_init_backend() { /* #2382 Before trying to create a user GUC, make sure */ @@ -110,19 +192,19 @@ void lwgeom_init_backend() /* already be loaded in memory and the GUC already defined. We */ /* can skip GUC definition in this case, so we just return. */ static const char *guc_name = "postgis.backend"; - const char *guc_installed = GetConfigOption(guc_name, TRUE, FALSE); - + // const char *guc_installed = GetConfigOption(guc_name, TRUE, FALSE); + /* Uh oh, this GUC name already exists. Ordinarily we could just go on */ /* our way, but the way the postgis.backend works is by using the "assign" */ /* callback to change which backend is in use by flipping a global variable */ /* over. This saves the overhead of looking up the engine every time, at */ /* the expense of the extra complexity. */ - if ( guc_installed ) + if ( guc_find_option(guc_name) ) { /* In this narrow case the previously installed GUC is tied to the callback in */ /* the previously loaded library. Probably this is happening during an */ /* upgrade, so the old library is where the callback ties to. */ - elog(WARNING, "'%s' is currently set to '%s' and cannot be changed until you reconnect", guc_name, guc_installed); + elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", guc_name); return; } @@ -143,6 +225,19 @@ void lwgeom_init_backend() ); } +#if 0 + +backend/utils/misc/guc.h +int GetNumConfigOptions(void) returns num_guc_variables + +backend/utils/misc/guc_tables.h +struct config_generic ** get_guc_variables(void) + + + + +#endif + PG_FUNCTION_INFO_V1(intersects); Datum intersects(PG_FUNCTION_ARGS) {