diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 7690da0e67..600e6c7243 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.16 2009/01/06 14:47:37 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.17 2009/01/08 19:34:41 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -336,9 +336,15 @@ add_real_reloption(int kind, char *name, char *desc, double default_val, /* * add_string_reloption * Add a new string reloption + * + * "validator" is an optional function pointer that can be used to test the + * validity of the values. It must elog(ERROR) when the argument string is + * not acceptable for the variable. Note that the default value must pass + * the validation. */ void -add_string_reloption(int kind, char *name, char *desc, char *default_val) +add_string_reloption(int kind, char *name, char *desc, char *default_val, + validate_string_relopt validator) { MemoryContext oldcxt; relopt_string *newoption; @@ -359,6 +365,7 @@ add_string_reloption(int kind, char *name, char *desc, char *default_val) newoption->gen.kind = kind; newoption->gen.namelen = strlen(name); newoption->gen.type = RELOPT_TYPE_STRING; + newoption->validate_cb = validator; if (default_val) { strcpy(newoption->default_val, default_val); @@ -372,6 +379,10 @@ add_string_reloption(int kind, char *name, char *desc, char *default_val) newoption->default_isnull = true; } + /* make sure the validator/default combination is sane */ + if (newoption->validate_cb) + (newoption->validate_cb) (newoption->default_val, true); + MemoryContextSwitchTo(oldcxt); add_reloption((relopt_gen *) newoption); @@ -729,10 +740,15 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, } break; case RELOPT_TYPE_STRING: - option->values.string_val = value; - nofree = true; - parsed = true; - /* no validation possible */ + { + relopt_string *optstring = (relopt_string *) option->gen; + + option->values.string_val = value; + nofree = true; + if (optstring->validate_cb) + (optstring->validate_cb) (value, validate); + parsed = true; + } break; default: elog(ERROR, "unsupported reloption type %d", option->gen->type); diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 5238c70904..5672cb4dcb 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -11,7 +11,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.8 2009/01/06 14:47:37 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/access/reloptions.h,v 1.9 2009/01/08 19:34:41 alvherre Exp $ * *------------------------------------------------------------------------- */ @@ -90,11 +90,14 @@ typedef struct relopt_real double max; } relopt_real; +typedef void (*validate_string_relopt) (char *value, bool validate); + typedef struct relopt_string { relopt_gen gen; int default_len; bool default_isnull; + validate_string_relopt validate_cb; char default_val[1]; /* variable length */ } relopt_string; @@ -113,7 +116,7 @@ typedef struct relopt_string * need this information. */ #define HAVE_RELOPTION(optname, option) \ - (pg_strncasecmp(option.gen->name, optname, option.gen->namelen) == 0) + (pg_strncasecmp(option.gen->name, optname, option.gen->namelen + 1) == 0) #define HANDLE_INT_RELOPTION(optname, var, option, wasset) \ do { \ @@ -141,7 +144,7 @@ typedef struct relopt_string } \ } while (0) -#define HANDLE_REAL_RELOPTION(optname, var, option, wasset) \ +#define HANDLE_REAL_RELOPTION(optname, var, option, wasset) \ do { \ if (HAVE_RELOPTION(optname, option)) \ { \ @@ -166,23 +169,23 @@ typedef struct relopt_string * string options have been processed. */ #define HANDLE_STRING_RELOPTION(optname, var, option, base, offset, wasset) \ - do { \ + do { \ if (HAVE_RELOPTION(optname, option)) \ { \ relopt_string *optstring = (relopt_string *) option.gen;\ - char *string_val = NULL; \ - \ + char *string_val; \ if (option.isset) \ string_val = option.values.string_val; \ else if (!optstring->default_isnull) \ string_val = optstring->default_val; \ + else \ + string_val = NULL; \ (wasset) != NULL ? *(wasset) = option.isset : (dummyret) NULL; \ - \ - if (!string_val) \ + if (string_val == NULL) \ var = 0; \ else \ { \ - strcpy((char *)(base) + (offset), string_val); \ + strcpy(((char *)(base)) + (offset), string_val); \ var = (offset); \ (offset) += strlen(string_val) + 1; \ } \ @@ -190,6 +193,24 @@ typedef struct relopt_string } \ } while (0) +/* + * For use during amoptions: get the strlen of a string option + * (either default or the user defined value) + */ +#define GET_STRING_RELOPTION_LEN(option) \ + ((option).isset ? strlen((option).values.string_val) : \ + ((relopt_string *) (option).gen)->default_len) + +/* + * For use by code reading options already parsed: get a pointer to the string + * value itself. "optstruct" is the StdRdOption struct or equivalent, "member" + * is the struct member corresponding to the string option + */ +#define GET_STRING_RELOPTION(optstruct, member) \ + ((optstruct)->member == 0 ? NULL : \ + (char *)(optstruct) + (optstruct)->member) + + extern int add_reloption_kind(void); extern void add_bool_reloption(int kind, char *name, char *desc, bool default_val); @@ -198,7 +219,7 @@ extern void add_int_reloption(int kind, char *name, char *desc, extern void add_real_reloption(int kind, char *name, char *desc, double default_val, double min_val, double max_val); extern void add_string_reloption(int kind, char *name, char *desc, - char *default_val); + char *default_val, validate_string_relopt validator); extern Datum transformRelOptions(Datum oldOptions, List *defList, bool ignoreOids, bool isReset);