A couple further reloptions improvements, per KaiGai Kohei: add a validation
authorAlvaro Herrera
Thu, 8 Jan 2009 19:34:41 +0000 (19:34 +0000)
committerAlvaro Herrera
Thu, 8 Jan 2009 19:34:41 +0000 (19:34 +0000)
function to the string type and add a couple of macros for string handling.

In passing, fix an off-by-one bug of mine.

src/backend/access/common/reloptions.c
src/include/access/reloptions.h

index 7690da0e671a3b98aeda539e36d2dfac1fe5a3f3..600e6c7243dec323d75f732a7d80ccbd923e748d 100644 (file)
@@ -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);
index 5238c70904ac0c21f312cbb60b62125f6ee8d8da..5672cb4dcbfd6299e52aa80b1056827734c68f2f 100644 (file)
@@ -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);