1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Support reloptions of enum type

All our current in core relation options of type string (not many,
admittedly) behave in reality like enums.  But after seeing an
implementation for enum reloptions, it's clear that strings are messier,
so introduce the new reloption type.  Switch all string options to be
enums instead.

Fortunately we have a recently introduced test module for reloptions, so
we don't lose coverage of string reloptions, which may still be used by
third-party modules.

Authors: Nikolay Shaplov, Álvaro Herrera
Reviewed-by: Nikita Glukhov, Aleksandr Parfenov
Discussion: https://postgr.es/m/43332102.S2V5pIjXRx@x200m
This commit is contained in:
Alvaro Herrera
2019-09-25 15:56:52 -03:00
parent caba97a9d9
commit 773df883e8
12 changed files with 214 additions and 75 deletions

View File

@ -433,7 +433,25 @@ static relopt_real realRelOpts[] =
{{NULL}}
};
static relopt_string stringRelOpts[] =
/* values from GistOptBufferingMode */
relopt_enum_elt_def gistBufferingOptValues[] =
{
{"auto", GIST_OPTION_BUFFERING_AUTO},
{"on", GIST_OPTION_BUFFERING_ON},
{"off", GIST_OPTION_BUFFERING_OFF},
{(const char *) NULL} /* list terminator */
};
/* values from ViewOptCheckOption */
relopt_enum_elt_def viewCheckOptValues[] =
{
/* no value for NOT_SET */
{"local", VIEW_OPTION_CHECK_OPTION_LOCAL},
{"cascaded", VIEW_OPTION_CHECK_OPTION_CASCADED},
{(const char *) NULL} /* list terminator */
};
static relopt_enum enumRelOpts[] =
{
{
{
@ -442,10 +460,9 @@ static relopt_string stringRelOpts[] =
RELOPT_KIND_GIST,
AccessExclusiveLock
},
4,
false,
gistValidateBufferingOption,
"auto"
gistBufferingOptValues,
GIST_OPTION_BUFFERING_AUTO,
gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")
},
{
{
@ -454,15 +471,20 @@ static relopt_string stringRelOpts[] =
RELOPT_KIND_VIEW,
AccessExclusiveLock
},
0,
true,
validateWithCheckOption,
NULL
viewCheckOptValues,
VIEW_OPTION_CHECK_OPTION_NOT_SET,
gettext_noop("Valid values are \"local\" and \"cascaded\".")
},
/* list terminator */
{{NULL}}
};
static relopt_string stringRelOpts[] =
{
/* list terminator */
{{NULL}}
};
static relopt_gen **relOpts = NULL;
static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT;
@ -505,6 +527,12 @@ initialize_reloptions(void)
realRelOpts[i].gen.lockmode));
j++;
}
for (i = 0; enumRelOpts[i].gen.name; i++)
{
Assert(DoLockModesConflict(enumRelOpts[i].gen.lockmode,
enumRelOpts[i].gen.lockmode));
j++;
}
for (i = 0; stringRelOpts[i].gen.name; i++)
{
Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode,
@ -543,6 +571,14 @@ initialize_reloptions(void)
j++;
}
for (i = 0; enumRelOpts[i].gen.name; i++)
{
relOpts[j] = &enumRelOpts[i].gen;
relOpts[j]->type = RELOPT_TYPE_ENUM;
relOpts[j]->namelen = strlen(relOpts[j]->name);
j++;
}
for (i = 0; stringRelOpts[i].gen.name; i++)
{
relOpts[j] = &stringRelOpts[i].gen;
@ -641,6 +677,9 @@ allocate_reloption(bits32 kinds, int type, const char *name, const char *desc,
case RELOPT_TYPE_REAL:
size = sizeof(relopt_real);
break;
case RELOPT_TYPE_ENUM:
size = sizeof(relopt_enum);
break;
case RELOPT_TYPE_STRING:
size = sizeof(relopt_string);
break;
@ -661,6 +700,13 @@ allocate_reloption(bits32 kinds, int type, const char *name, const char *desc,
newoption->type = type;
newoption->lockmode = lockmode;
/*
* Set the default lock mode for this option. There is no actual way
* for a module to enforce it when declaring a custom relation option,
* so just use the highest level, which is safe for all cases.
*/
newoption->lockmode = AccessExclusiveLock;
MemoryContextSwitchTo(oldcxt);
return newoption;
@ -721,6 +767,34 @@ add_real_reloption(bits32 kinds, const char *name, const char *desc, double defa
add_reloption((relopt_gen *) newoption);
}
/*
* add_enum_reloption
* Add a new enum reloption
*
* The members array must have a terminating NULL entry.
*
* The detailmsg is shown when unsupported values are passed, and has this
* form: "Valid values are \"foo\", \"bar\", and \"bar\"."
*
* The members array and detailmsg are not copied -- caller must ensure that
* they are valid throughout the life of the process.
*/
void
add_enum_reloption(bits32 kinds, const char *name, const char *desc,
relopt_enum_elt_def *members, int default_val,
const char *detailmsg, LOCKMODE lockmode)
{
relopt_enum *newoption;
newoption = (relopt_enum *) allocate_reloption(kinds, RELOPT_TYPE_ENUM,
name, desc, lockmode);
newoption->members = members;
newoption->default_val = default_val;
newoption->detailmsg = detailmsg;
add_reloption((relopt_gen *) newoption);
}
/*
* add_string_reloption
* Add a new string reloption
@ -1237,6 +1311,37 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
optreal->min, optreal->max)));
}
break;
case RELOPT_TYPE_ENUM:
{
relopt_enum *optenum = (relopt_enum *) option->gen;
relopt_enum_elt_def *elt;
parsed = false;
for (elt = optenum->members; elt->string_val; elt++)
{
if (pg_strcasecmp(value, elt->string_val) == 0)
{
option->values.enum_val = elt->symbol_val;
parsed = true;
break;
}
}
if (validate && !parsed)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid value for enum option \"%s\": %s",
option->gen->name, value),
optenum->detailmsg ?
errdetail_internal("%s", _(optenum->detailmsg)) : 0));
/*
* If value is not among the allowed string values, but we are
* not asked to validate, just use the default numeric value.
*/
if (!parsed)
option->values.enum_val = optenum->default_val;
}
break;
case RELOPT_TYPE_STRING:
{
relopt_string *optstring = (relopt_string *) option->gen;
@ -1330,6 +1435,11 @@ fillRelOptions(void *rdopts, Size basesize,
options[i].values.real_val :
((relopt_real *) options[i].gen)->default_val;
break;
case RELOPT_TYPE_ENUM:
*(int *) itempos = options[i].isset ?
options[i].values.enum_val :
((relopt_enum *) options[i].gen)->default_val;
break;
case RELOPT_TYPE_STRING:
optstring = (relopt_string *) options[i].gen;
if (options[i].isset)
@ -1446,8 +1556,8 @@ view_reloptions(Datum reloptions, bool validate)
static const relopt_parse_elt tab[] = {
{"security_barrier", RELOPT_TYPE_BOOL,
offsetof(ViewOptions, security_barrier)},
{"check_option", RELOPT_TYPE_STRING,
offsetof(ViewOptions, check_option_offset)}
{"check_option", RELOPT_TYPE_ENUM,
offsetof(ViewOptions, check_option)}
};
options = parseRelOptions(reloptions, validate, RELOPT_KIND_VIEW, &numoptions);