On Mon, Oct 28, 2019 at 05:16:54PM +0900, Amit Langote wrote: > On Sat, Oct 26, 2019 at 11:45 AM Michael Paquier <[email protected]> wrote: >> On Fri, Oct 25, 2019 at 04:42:24PM +0900, Amit Langote wrote: >> > Hmm, if we're inventing a new API to replace the old one, why not use >> > that opportunity to be consistent with our general style, which >> > predominantly seems to be either words_separated_by_underscore() or >> > UpperCamelCase(). Thoughts? >> >> Not wrong. Using small-case characters separated with underscores >> would be more consistent with the rest perhaps? We use that for the >> initialization of custom variables and for all the relkind-related >> interfaces. > > OK, I went with build_reloptions(), which looks very similar to nearby > exported functions.
Thanks. >> + * Parses reloptions provided by the caller in text array format and >> + * fills and returns a struct containing the parsed option values >> The sentence structure is weird, perhaps: >> This routine parses "reloptions" provided by the caller in text-array >> format. The parsing is done with a table describing the allowed >> options, defined by "relopt_elems" of length "num_relopt_elems". The >> returned result is a structure containing all the parsed option >> values. > > Thanks, I have expanded the header comment based on your text. Looks fine. I have done some refinements as per the attached. Running the regression tests of dummy_index_am has proved to be able to break the assertion you have added. I don't have a good idea of how to make that more simple and reliable, but there is one thing outstanding here: the number of options parsed by parseRelOptions should never be higher than num_relopt_elems. So let's at least be safer about that. Also if some options are parsed options will never be NULL, so there is no need to check for it before pfree()-ing it, no? Any comments from others? Alvaro perhaps? -- Michael
diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
index 3d44616adc..e2063bac62 100644
--- a/contrib/bloom/blutils.c
+++ b/contrib/bloom/blutils.c
@@ -475,18 +475,18 @@ BloomInitMetapage(Relation index)
bytea *
bloptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- int numoptions;
BloomOptions *rdopts;
/* Parse the user-given reloptions */
- options = parseRelOptions(reloptions, validate, bl_relopt_kind, &numoptions);
- rdopts = allocateReloptStruct(sizeof(BloomOptions), options, numoptions);
- fillRelOptions((void *) rdopts, sizeof(BloomOptions), options, numoptions,
- validate, bl_relopt_tab, lengthof(bl_relopt_tab));
+ rdopts = (BloomOptions *) build_reloptions(reloptions, validate,
+ bl_relopt_kind,
+ sizeof(BloomOptions),
+ bl_relopt_tab,
+ lengthof(bl_relopt_tab));
/* Convert signature length from # of bits to # to words, rounding up */
- rdopts->bloomLength = (rdopts->bloomLength + SIGNWORDBITS - 1) / SIGNWORDBITS;
+ if (rdopts)
+ rdopts->bloomLength = (rdopts->bloomLength + SIGNWORDBITS - 1) / SIGNWORDBITS;
return (bytea *) rdopts;
}
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index ae7b729edd..b4f681a79e 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -820,29 +820,15 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
bytea *
brinoptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- BrinOptions *rdopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"pages_per_range", RELOPT_TYPE_INT, offsetof(BrinOptions, pagesPerRange)},
{"autosummarize", RELOPT_TYPE_BOOL, offsetof(BrinOptions, autosummarize)}
};
- options = parseRelOptions(reloptions, validate, RELOPT_KIND_BRIN,
- &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- rdopts = allocateReloptStruct(sizeof(BrinOptions), options, numoptions);
-
- fillRelOptions((void *) rdopts, sizeof(BrinOptions), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) rdopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ RELOPT_KIND_BRIN,
+ sizeof(BrinOptions),
+ tab, lengthof(tab));
}
/*
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index b5072c00fe..94c0029a0a 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -495,6 +495,14 @@ static bool need_initialization = true;
static void initialize_reloptions(void);
static void parse_one_reloption(relopt_value *option, char *text_str,
int text_len, bool validate);
+static relopt_value *parseRelOptions(Datum options, bool validate,
+ relopt_kind kind, int *numrelopts);
+static void *allocateReloptStruct(Size base, relopt_value *options,
+ int numoptions);
+static void fillRelOptions(void *rdopts, Size basesize,
+ relopt_value *options, int numoptions,
+ bool validate,
+ const relopt_parse_elt *elems, int nelems);
/*
* initialize_reloptions
@@ -1121,6 +1129,55 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
return options;
}
+/*
+ * build_reloptions
+ *
+ * Parses "reloptions" provided by the caller, returning them in a
+ * structure containing the parsed options. The parsing is done with
+ * the help of a "parsing table" describing the allowed options, defined
+ * by "relopt_elems" of length "num_relopt_elems".
+ *
+ * "validate" must be true if reloptions value is freshly built by
+ * transformRelOptions(), as opposed to being read from the catalog, in which
+ * case the values contained in it must already be valid.
+ *
+ * The result is a structure containing all the parsed option values in
+ * text-array format. NULL is returned if the passed-in options did not
+ * match any of the options in the parsing table, unless validate is true
+ * in which case an error would be reported.
+ */
+void *
+build_reloptions(Datum reloptions, bool validate,
+ relopt_kind kind,
+ Size relopt_struct_size,
+ const relopt_parse_elt *relopt_elems,
+ int num_relopt_elems)
+{
+ int numoptions;
+ relopt_value *options;
+ void *rdopts;
+
+ /* Parse options specific to given relopt_kind. */
+ options = parseRelOptions(reloptions, validate, kind, &numoptions);
+ Assert(numoptions <= num_relopt_elems);
+
+ /* If none set, we're done. */
+ if (numoptions == 0)
+ {
+ Assert(options == NULL);
+ return NULL;
+ }
+
+ /* Allocate and fill the structure. */
+ rdopts = allocateReloptStruct(relopt_struct_size, options, numoptions);
+ fillRelOptions(rdopts, relopt_struct_size, options, numoptions,
+ validate, relopt_elems, num_relopt_elems);
+
+ pfree(options);
+
+ return rdopts;
+}
+
/*
* Interpret reloptions that are given in text-array format.
*
@@ -1140,7 +1197,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
* returned array. Values of type string are allocated separately and must
* be freed by the caller.
*/
-relopt_value *
+static relopt_value *
parseRelOptions(Datum options, bool validate, relopt_kind kind,
int *numrelopts)
{
@@ -1365,7 +1422,7 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
* "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
* equivalent).
*/
-void *
+static void *
allocateReloptStruct(Size base, relopt_value *options, int numoptions)
{
Size size = base;
@@ -1389,7 +1446,7 @@ allocateReloptStruct(Size base, relopt_value *options, int numoptions)
* elems, of length numelems, is the table describing the allowed options.
* When validate is true, it is expected that all options appear in elems.
*/
-void
+static void
fillRelOptions(void *rdopts, Size basesize,
relopt_value *options, int numoptions,
bool validate,
@@ -1474,9 +1531,6 @@ fillRelOptions(void *rdopts, Size basesize,
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{
- relopt_value *options;
- StdRdOptions *rdopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
@@ -1521,20 +1575,9 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
offsetof(StdRdOptions, vacuum_truncate)}
};
- options = parseRelOptions(reloptions, validate, kind, &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions);
-
- fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) rdopts;
+ return (bytea *) build_reloptions(reloptions, validate, kind,
+ sizeof(StdRdOptions),
+ tab, lengthof(tab));
}
/*
@@ -1543,9 +1586,6 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
bytea *
view_reloptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- ViewOptions *vopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"security_barrier", RELOPT_TYPE_BOOL,
offsetof(ViewOptions, security_barrier)},
@@ -1553,20 +1593,10 @@ view_reloptions(Datum reloptions, bool validate)
offsetof(ViewOptions, check_option)}
};
- options = parseRelOptions(reloptions, validate, RELOPT_KIND_VIEW, &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- vopts = allocateReloptStruct(sizeof(ViewOptions), options, numoptions);
-
- fillRelOptions((void *) vopts, sizeof(ViewOptions), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) vopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ RELOPT_KIND_VIEW,
+ sizeof(ViewOptions),
+ tab, lengthof(tab));
}
/*
@@ -1628,29 +1658,15 @@ index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
bytea *
attribute_reloptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- AttributeOpts *aopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"n_distinct", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct)},
{"n_distinct_inherited", RELOPT_TYPE_REAL, offsetof(AttributeOpts, n_distinct_inherited)}
};
- options = parseRelOptions(reloptions, validate, RELOPT_KIND_ATTRIBUTE,
- &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- aopts = allocateReloptStruct(sizeof(AttributeOpts), options, numoptions);
-
- fillRelOptions((void *) aopts, sizeof(AttributeOpts), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) aopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ RELOPT_KIND_ATTRIBUTE,
+ sizeof(AttributeOpts),
+ tab, lengthof(tab));
}
/*
@@ -1659,30 +1675,16 @@ attribute_reloptions(Datum reloptions, bool validate)
bytea *
tablespace_reloptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- TableSpaceOpts *tsopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)},
{"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)},
{"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}
};
- options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE,
- &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- tsopts = allocateReloptStruct(sizeof(TableSpaceOpts), options, numoptions);
-
- fillRelOptions((void *) tsopts, sizeof(TableSpaceOpts), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) tsopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ RELOPT_KIND_TABLESPACE,
+ sizeof(TableSpaceOpts),
+ tab, lengthof(tab));
}
/*
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index cf9699ad18..38593554f0 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -602,30 +602,16 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
bytea *
ginoptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- GinOptions *rdopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
{"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
pendingListCleanupSize)}
};
- options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN,
- &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions);
-
- fillRelOptions((void *) rdopts, sizeof(GinOptions), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) rdopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ RELOPT_KIND_GIN,
+ sizeof(GinOptions),
+ tab, lengthof(tab));
}
/*
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 45804d7a91..a23dec76a2 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -908,29 +908,15 @@ gistPageRecyclable(Page page)
bytea *
gistoptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- GiSTOptions *rdopts;
- int numoptions;
static const relopt_parse_elt tab[] = {
{"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
{"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
};
- options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIST,
- &numoptions);
-
- /* if none set, we're done */
- if (numoptions == 0)
- return NULL;
-
- rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions);
-
- fillRelOptions((void *) rdopts, sizeof(GiSTOptions), options, numoptions,
- validate, tab, lengthof(tab));
-
- pfree(options);
-
- return (bytea *) rdopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ RELOPT_KIND_GIST,
+ sizeof(GiSTOptions),
+ tab, lengthof(tab));
}
/*
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 6bde2093d6..d4f6a168bd 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -25,7 +25,10 @@
#include "nodes/pg_list.h"
#include "storage/lock.h"
-/* types supported by reloptions */
+/*
+ * Types supported by reloptions. NB: when changing this, see
+ * BuildRelOptions().
+ */
typedef enum relopt_type
{
RELOPT_TYPE_BOOL,
@@ -288,14 +291,12 @@ extern Datum transformRelOptions(Datum oldOptions, List *defList,
extern List *untransformRelOptions(Datum options);
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
amoptions_function amoptions);
-extern relopt_value *parseRelOptions(Datum options, bool validate,
- relopt_kind kind, int *numrelopts);
-extern void *allocateReloptStruct(Size base, relopt_value *options,
- int numoptions);
-extern void fillRelOptions(void *rdopts, Size basesize,
- relopt_value *options, int numoptions,
- bool validate,
- const relopt_parse_elt *elems, int nelems);
+
+extern void *build_reloptions(Datum reloptions, bool validate,
+ relopt_kind kind,
+ Size relopt_struct_size,
+ const relopt_parse_elt *relopt_elems,
+ int num_relopt_elems);
extern bytea *default_reloptions(Datum reloptions, bool validate,
relopt_kind kind);
diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c
index bc68767f3a..053636e4b4 100644
--- a/src/test/modules/dummy_index_am/dummy_index_am.c
+++ b/src/test/modules/dummy_index_am/dummy_index_am.c
@@ -222,17 +222,10 @@ dicostestimate(PlannerInfo *root, IndexPath *path, double loop_count,
static bytea *
dioptions(Datum reloptions, bool validate)
{
- relopt_value *options;
- int numoptions;
- DummyIndexOptions *rdopts;
-
- /* Parse the user-given reloptions */
- options = parseRelOptions(reloptions, validate, di_relopt_kind, &numoptions);
- rdopts = allocateReloptStruct(sizeof(DummyIndexOptions), options, numoptions);
- fillRelOptions((void *) rdopts, sizeof(DummyIndexOptions), options, numoptions,
- validate, di_relopt_tab, lengthof(di_relopt_tab));
-
- return (bytea *) rdopts;
+ return (bytea *) build_reloptions(reloptions, validate,
+ di_relopt_kind,
+ sizeof(DummyIndexOptions),
+ di_relopt_tab, lengthof(di_relopt_tab));
}
/*
signature.asc
Description: PGP signature
