DefineCustomTypeVariable函数是提供给插件定义GUC参数的函数。

struct config_int {
struct config_generic gen;
/* constant fields, must be set correctly in initial value: */
int *variable;
int boot_val;
int min;
int max;
GucIntCheckHook check_hook;
GucIntAssignHook assign_hook;
GucShowHook show_hook;
/* variable fields, initialized at runtime: */
int reset_val;
void *reset_extra;
};

以config_int为例,先调用init_custom_variable申请config_generic结构体,并初始化该结构体,该结构体是GUC五种类型GUC所共有的结构体。首先进行校验,对于PGC_POSTMASTER特征的GUC参数,只能在加载shared preload libraries时创建。还有两类情况检查一下,如下代码所示。

/* Common code for DefineCustomXXXVariable subroutines: allocate the new variable's config struct and fill in generic fields. */
static struct config_generic *init_custom_variable(const char *name, const char *short_desc, const char *long_desc, GucContext context, int flags, enum config_type type, size_t sz) {
struct config_generic *gen;
/* Only allow custom PGC_POSTMASTER variables to be created during shared
* library preload; any later than that, we can't ensure that the value
* doesn't change after startup. This is a fatal elog if it happens; just
* erroring out isn't safe because we don't know what the calling loadable
* module might already have hooked into. */
if (context == PGC_POSTMASTER && !process_shared_preload_libraries_in_progress) elog(FATAL, "cannot create PGC_POSTMASTER variables after startup");
/* We can't support custom GUC_LIST_QUOTE variables, because the wrong
* things would happen if such a variable were set or pg_dump'd when the
* defining extension isn't loaded. Again, treat this as fatal because
* the loadable module may be partly initialized already. */
if (flags & GUC_LIST_QUOTE) elog(FATAL, "extensions cannot define GUC_LIST_QUOTE variables");
/* Before pljava commit 398f3b876ed402bdaec8bc804f29e2be95c75139
* (2015-12-15), two of that module's PGC_USERSET variables facilitated
* trivial escalation to superuser privileges. Restrict the variables to
* protect sites that have yet to upgrade pljava. */
if (context == PGC_USERSET &&(strcmp(name, "pljava.classpath") == 0 || strcmp(name, "pljava.vmoptions") == 0)) context = PGC_SUSET;

gen = (struct config_generic *) guc_malloc(ERROR, sz); memset(gen, 0, sz);
gen->name = guc_strdup(ERROR, name); // 设置参数名
gen->context = context;
gen->group = CUSTOM_OPTIONS; // 用户定义参数
gen->short_desc = short_desc;
gen->long_desc = long_desc;
gen->flags = flags;
gen->vartype = type;
return gen;
}

PG守护进程(Postmaster)——DefineCustomTypeVariable定义GUC参数_java

DefineCustomIntVariable

DefineCustomIntVariable函数定义如下

void DefineCustomIntVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue,int minValue,int maxValue,GucContext context,int flags,GucIntCheckHook check_hook,GucIntAssignHook assign_hook,GucShowHook show_hook) {
struct config_int *var;
var = (struct config_int *)init_custom_variable(name, short_desc, long_desc, context, flags, PGC_INT, sizeof(struct config_int));
var->variable = valueAddr;
var->boot_val = bootValue; // 设置默认值
var->reset_val = bootValue;// 设置默认值
var->min = minValue;
var->max = maxValue;
var->check_hook = check_hook;
var->assign_hook = assign_hook;
var->show_hook = show_hook;
define_custom_variable(&var->gen);
}

define_custom_variable

define_custom_variable函数将新定义的GUC参数插入到GUC全局矩阵guc_variables。通过GUC参数名调用bsearch查询在guc_variables是否已经有该参数。如果没有,则调用InitializeOneGUCOption函数初始化GUC变量,并调用add_guc_variable函数将其加入GUC全局矩阵guc_variables。如果有,且参数没有定义GUC_CUSTOM_PLACEHOLDER,需要报错。

/* Common code for DefineCustomXXXVariable subroutines: insert the new variable into the GUC variable array, replacing any placeholder. */
static void define_custom_variable(struct config_generic *variable) {
const char *name = variable->name;
const char **nameAddr = &name;
struct config_string *pHolder;
struct config_generic **res;

/* See if there's a placeholder by the same name. */
res = (struct config_generic **) bsearch((void *) &nameAddr, (void *) guc_variables, num_guc_variables, sizeof(struct config_generic *), guc_var_compare);
if (res == NULL){
/* No placeholder to replace, so we can just add it ... but first, make sure it's initialized to its default value. */
InitializeOneGUCOption(variable);
add_guc_variable(variable, ERROR);
return;
}

/* This better be a placeholder */
if (((*res)->flags & GUC_CUSTOM_PLACEHOLDER) == 0)
ereport(ERROR,(errcode(ERRCODE_INTERNAL_ERROR),errmsg("attempt to redefine parameter \"%s\"", name)));

如果有,且参数定义GUC_CUSTOM_PLACEHOLDER,只有sring类型的GUC参数能够继续处理。先将输入的GUC参数值设置为默认值。将GUC全局矩阵guc_variables的槽给输入的GUC参数。

Assert((*res)->vartype == PGC_STRING);
pHolder = (struct config_string *) (*res);
/* First, set the variable to its default value. We must do this even though we intend to immediately apply a new value, since it's possible that the new value is invalid. */
InitializeOneGUCOption(variable);
/* Replace the placeholder. We aren't changing the name, so no re-sorting is necessary */
*res = variable;

先设置输入的GUC参数值设置为reset值,应用当前值,其他一些设置项。

/* Assign the string value(s) stored in the placeholder to the real
* variable. Essentially, we need to duplicate all the active and stacked
* values, but with appropriate validation and datatype adjustment.
* If an assignment fails, we report a WARNING and keep going. We don't
* want to throw ERROR for bad values, because it'd bollix the add-on
* module that's presumably halfway through getting loaded. In such cases
* the default or previous state will become active instead. */
/* First, apply the reset value if any */
if (pHolder->reset_val)
(void) set_config_option(name, pHolder->reset_val, pHolder->gen.reset_scontext, pHolder->gen.reset_source, GUC_ACTION_SET, true, WARNING, false);
/* That should not have resulted in stacking anything */
Assert(variable->stack == NULL);

/* Now, apply current and stacked values, in the order they were stacked */
reapply_stacked_values(variable, pHolder, pHolder->gen.stack,*(pHolder->variable),pHolder->gen.scontext, pHolder->gen.source);

/* Also copy over any saved source-location information */
if (pHolder->gen.sourcefile)
set_config_sourcefile(name, pHolder->gen.sourcefile, pHolder->gen.sourceline);

/*
* Free up as much as we conveniently can of the placeholder structure.
* (This neglects any stack items, so it's possible for some memory to be
* leaked. Since this can only happen once per session per variable, it
* doesn't seem worth spending much code on.)
*/
set_string_field(pHolder, pHolder->variable, NULL);
set_string_field(pHolder, &pHolder->reset_val, NULL);

free(pHolder);
}

PG守护进程(Postmaster)——DefineCustomTypeVariable定义GUC参数_java_02