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:
@ -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);
|
||||
|
Reference in New Issue
Block a user