Re: autovacuum and reloptions

Поиск
Список
Период
Сортировка
От Euler Taveira de Oliveira
Тема Re: autovacuum and reloptions
Дата
Msg-id 48F53EC0.3020004@timbira.com
обсуждение исходный текст
Ответ на autovacuum and reloptions  (Alvaro Herrera <alvherre@alvh.no-ip.org>)
Ответы Re: autovacuum and reloptions  (Alvaro Herrera <alvherre@commandprompt.com>)
Re: autovacuum and reloptions  (Alvaro Herrera <alvherre@commandprompt.com>)
Список pgsql-hackers
Alvaro Herrera escreveu:
> So I gave up waiting for someone else to do the reloptions patch for
> autovacuum and started work on it myself.  What I soon discovered is
> that on first blush it seems a lot easier than I had expected.
>
Sorry about that. :( I was swamped with PGCon Brasil and then I took
some days to rest. I'm expecting to finish it before next CF.

What did I already do? I refactored reloptions.c to support multiple
options. I tried to follow up the same way GUC do (of course, it is much
 simpler). I'm thinking about removing (replacing?) StdRdOptions 'cause
we need a different struct to store reloptions. Suggestions?

I'm attaching the WIP patch so you can comment on it. I want to continue
working on it but I'm afraid you already did more than I do (in this
case, let me know for not duplicating efforts).


--
  Euler Taveira de Oliveira
  http://www.timbira.com/
Index: src/backend/access/common/reloptions.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/common/reloptions.c,v
retrieving revision 1.11
diff -c -r1.11 reloptions.c
*** src/backend/access/common/reloptions.c    23 Jul 2008 17:29:53 -0000    1.11
--- src/backend/access/common/reloptions.c    10 Oct 2008 13:55:15 -0000
***************
*** 24,29 ****
--- 24,182 ----
  #include "utils/guc.h"
  #include "utils/rel.h"

+ /*
+  * Contents of pg_class.reloptions
+  *
+  * To add an option:
+  *
+  * (i) decide on a class (integer, double, bool), name, default value, upper
+  * and lower bounds (if applicable).
+  *
+  * (ii) add a record below.
+  *
+  * (iii) don't forget to document the option
+  */
+
+ static struct relopt_bool    relOptBools[] =
+ {
+     {
+         {
+             "autovacuum_enabled",
+             "Enables autovacuum in this relation",
+             RO_BOOL
+         },
+         false
+     },
+     /* End-of-list marker */
+     {
+         {
+             NULL,
+             NULL,
+             RO_BOOL
+         },
+         false
+     }
+ };
+
+ static struct relopt_int    relOptInts[] =
+ {
+     {
+         {
+             "fillfactor",
+             "Packs table pages only to this percentage",
+             RO_INT
+         },
+         100,
+         10,
+         100
+     },
+     {
+         {
+             "autovacuum_vac_base_thresh",
+             "Minimum number of tuple updates or deletes prior to vacuum",
+             RO_INT
+         },
+         50,
+         0,
+         INT_MAX
+     },
+     {
+         {
+             "autovacuum_anl_base_thresh",
+             "Minimum number of tuple inserts, updates or deletes prior to analyze",
+             RO_INT
+         },
+         50,
+         0,
+         INT_MAX
+     },
+     {
+         {
+             "autovacuum_vac_cost_delay",
+             "Vacuum cost delay in milliseconds, for autovacuum",
+             RO_INT
+         },
+         20,
+         -1,
+         1000
+     },
+     {
+         {
+             "autovacuum_vac_cost_limit",
+             "Vacuum cost ammount available before napping, for autovacuum",
+             RO_INT
+         },
+         -1,
+         -1,
+         10000
+     },
+     {
+         {
+             "autovacuum_freeze_min_age",
+             "Minimum age at which VACUUM should freeze a table row, for autovacuum",
+             RO_INT
+         },
+         100000000,
+         0,
+         1000000000
+     },
+     {
+         {
+             "autovacuum_freeze_max_age",
+             "Age at which to autovacuum a table to prevent transaction ID wraparound",
+             RO_INT
+         },
+         200000000,
+         100000000,
+         2000000000
+     },
+     /* End-of-list marker */
+     {
+         {
+             NULL,
+             NULL,
+             RO_INT
+         },
+         0,
+         0,
+         0
+     }
+ };
+
+ struct relopt_real    relOptReals[] =
+ {
+     {
+         {
+             "autovacuum_vac_scale_factor",
+             "Number of tuples inserts, updates or deletes prior to vacuum as a fraction of reltuples",
+             RO_REAL
+         },
+         0.2,
+         0.0,
+         100.0
+     },
+     {
+         {
+             "autovacuum_anl_scale_factor",
+             "Number of tuples inserts, updates or deletes prior to analyze as a fraction of reltuples",
+             RO_REAL
+         },
+         0.1,
+         0.0,
+         100.0
+     },
+     /* End-of-list marker */
+     {
+         {
+             NULL,
+             NULL,
+             RO_REAL
+         },
+         0.0,
+         0.0,
+         0.0
+     }
+ };

  /*
   * Transform a relation options list (list of DefElem) into the text array
***************
*** 51,56 ****
--- 204,212 ----
      ArrayBuildState *astate;
      ListCell   *cell;

+     ereport(DEBUG2,
+             (errmsg("starting transformRelOptions() ...")));
+
      /* no change if empty list */
      if (defList == NIL)
          return oldOptions;
***************
*** 77,82 ****
--- 233,243 ----
              char       *text_str = VARDATA(oldoption);
              int            text_len = VARSIZE(oldoption) - VARHDRSZ;

+             char *tmp = text_str;
+             tmp[text_len] = '\0';
+             ereport(DEBUG1,
+                     (errmsg("old reloption: %s", text_str)));
+
              /* Search for a match in defList */
              foreach(cell, defList)
              {
***************
*** 93,98 ****
--- 254,261 ----
                  astate = accumArrayResult(astate, oldoptions[i],
                                            false, TEXTOID,
                                            CurrentMemoryContext);
+                 ereport(DEBUG1,
+                         (errmsg("added old reloption: %s", tmp)));
              }
          }
      }
***************
*** 136,141 ****
--- 299,307 ----
              SET_VARSIZE(t, len);
              sprintf(VARDATA(t), "%s=%s", def->defname, value);

+             ereport(DEBUG1,
+                     (errmsg("added new reloption: %s=%s", def->defname, value)));
+
              astate = accumArrayResult(astate, PointerGetDatum(t),
                                        false, TEXTOID,
                                        CurrentMemoryContext);
***************
*** 147,152 ****
--- 313,321 ----
      else
          result = (Datum) 0;

+     ereport(DEBUG2,
+             (errmsg("ending transformRelOptions() ...")));
+
      return result;
  }

***************
*** 164,169 ****
--- 333,341 ----
      int            noptions;
      int            i;

+     ereport(DEBUG2,
+             (errmsg("starting untransformRelOptions() ...")));
+
      /* Nothing to do if no options */
      if (!PointerIsValid(DatumGetPointer(options)))
          return result;
***************
*** 188,196 ****
--- 360,375 ----
              *p++ = '\0';
              val = (Node *) makeString(pstrdup(p));
          }
+
+         ereport(DEBUG1,
+                 (errmsg("added reloption: %s=%s", s, p)));
+
          result = lappend(result, makeDefElem(pstrdup(s), val));
      }

+     ereport(DEBUG2,
+             (errmsg("ending untransformRelOptions() ...")));
+
      return result;
  }

***************
*** 199,206 ****
   * Interpret reloptions that are given in text-array format.
   *
   *    options: array of "keyword=value" strings, as built by transformRelOptions
-  *    numkeywords: number of legal keywords
-  *    keywords: the allowed keywords
   *    values: output area
   *    validate: if true, throw error for unrecognized keywords.
   *
--- 378,383 ----
***************
*** 209,221 ****
   * containing the corresponding value, or NULL if the keyword does not appear.
   */
  void
! parseRelOptions(Datum options, int numkeywords, const char *const * keywords,
!                 char **values, bool validate)
  {
      ArrayType  *array;
      Datum       *optiondatums;
      int            noptions;
      int            i;

      /* Initialize to "all defaulted" */
      MemSet(values, 0, numkeywords * sizeof(char *));
--- 386,410 ----
   * containing the corresponding value, or NULL if the keyword does not appear.
   */
  void
! parseRelOptions(Datum options, char **values, bool validate, int minFillfactor)
  {
      ArrayType  *array;
      Datum       *optiondatums;
      int            noptions;
      int            i;
+     int            numkeywords = 0;
+
+     ereport(DEBUG2,
+             (errmsg("starting parseRelOptions() ...")));
+
+     for (i = 0; relOptBools[i].gen.name; i++)
+         numkeywords++;
+     for (i = 0; relOptInts[i].gen.name; i++)
+         numkeywords++;
+     for (i = 0; relOptReals[i].gen.name; i++)
+         numkeywords++;
+     ereport(DEBUG1,
+             (errmsg("number of keywords: %d", numkeywords)));

      /* Initialize to "all defaulted" */
      MemSet(values, 0, numkeywords * sizeof(char *));
***************
*** 236,267 ****
          text       *optiontext = DatumGetTextP(optiondatums[i]);
          char       *text_str = VARDATA(optiontext);
          int            text_len = VARSIZE(optiontext) - VARHDRSZ;
!         int            j;

          /* Search for a match in keywords */
!         for (j = 0; j < numkeywords; j++)
          {
!             int            kw_len = strlen(keywords[j]);

              if (text_len > kw_len && text_str[kw_len] == '=' &&
!                 pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
              {
!                 char       *value;
!                 int            value_len;

                  if (values[j] && validate)
                      ereport(ERROR,
                              (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                           errmsg("parameter \"%s\" specified more than once",
!                                  keywords[j])));
                  value_len = text_len - kw_len - 1;
                  value = (char *) palloc(value_len + 1);
                  memcpy(value, text_str + kw_len + 1, value_len);
                  value[value_len] = '\0';
                  values[j] = value;
                  break;
              }
          }
          if (j >= numkeywords && validate)
          {
              char       *s;
--- 425,574 ----
          text       *optiontext = DatumGetTextP(optiondatums[i]);
          char       *text_str = VARDATA(optiontext);
          int            text_len = VARSIZE(optiontext) - VARHDRSZ;
!         int            j = 0;
!         bool        found = false;
!
!         char *tmp = text_str;
!         tmp[text_len] = '\0';
!         ereport(DEBUG1,
!                 (errmsg("parsing reloption %s ...", tmp)));

          /* Search for a match in keywords */
!         while (relOptBools[j].gen.name)
          {
!             int        kw_len = strlen(relOptBools[j].gen.name);

              if (text_len > kw_len && text_str[kw_len] == '=' &&
!                 pg_strcasecmp(text_str, relOptBools[j].gen.name, kw_len) == 0)
              {
!                 char    *value;
!                 int        value_len;

                  if (values[j] && validate)
                      ereport(ERROR,
                              (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
!                         errmsg("parameter \"%s\" specified more than once",
!                                 relOptBools[j].gen.name)));
!
                  value_len = text_len - kw_len - 1;
                  value = (char *) palloc(value_len + 1);
                  memcpy(value, text_str + kw_len + 1, value_len);
                  value[value_len] = '\0';
+
+                 if (parse_bool(value, NULL) == false && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                              errmsg("invalid input value for parameter %s: \"%s\"",
+                                     relOptBools[j].gen.name, value),
+                              errhint("value must be a boolean")));
+
                  values[j] = value;
+
+                 found = true;
                  break;
              }
+
+             j++;
          }
+
+         while (relOptInts[j].gen.name || !found)
+         {
+             int        kw_len = strlen(relOptInts[j].gen.name);
+
+             if (text_len > kw_len && text_str[kw_len] == '=' &&
+                 pg_strcasecmp(text_str, relOptInts[j].gen.name, kw_len) == 0)
+             {
+                 char    *value;
+                 int        value_len;
+
+                 if (values[j] && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                         errmsg("parameter \"%s\" specified more than once",
+                                 relOptInts[j].gen.name)));
+
+                 value_len = text_len - kw_len - 1;
+                 value = (char *) palloc(value_len + 1);
+                 memcpy(value, text_str + kw_len + 1, value_len);
+                 value[value_len] = '\0';
+
+                 if (parse_int(value, NULL, 0, NULL) == false && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                              errmsg("invalid input value for parameter %s: \"%s\"",
+                                     relOptBools[j].gen.name, value),
+                              errhint("value must be an integer")));
+
+                 if ((value < relOptInts[j].min || value > relOptInts[j].max) && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                              errmsg("%s=%s is out of range (should be between %d and %d)",
+                                     relOptInts[j].gen.name, value, relOptInts[j].min, relOptInts[j].max)));
+
+                 /*
+                  * Especial check for fillfactor because minimum fillfactor values
+                  * are AMs and/or heap dependant. We don't need to check upper
+                  * limit because we already did it above.
+                  */
+                 if (pg_strcasecmp(relOptInts[j].gen.name, "fillfactor") == 0 &&
+                         value < minFillfactor && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                              errmsg("fillfactor=%s is out of range (should be between %d and 100)",
+                                  value, minFillfactor)));
+
+                 values[j] = value;
+
+                 found = true;
+                 break;
+             }
+
+             j++;
+         }
+
+         while (relOptReals[j].gen.name || !found)
+         {
+             int        kw_len = strlen(relOptReals[j].gen.name);
+
+             if (text_len > kw_len && text_str[kw_len] == '=' &&
+                 pg_strcasecmp(text_str, relOptReals[j].gen.name, kw_len) == 0)
+             {
+                 char    *value;
+                 int        value_len;
+
+                 if (values[j] && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                         errmsg("parameter \"%s\" specified more than once",
+                                 relOptReals[j].gen.name)));
+
+                 value_len = text_len - kw_len - 1;
+                 value = (char *) palloc(value_len + 1);
+                 memcpy(value, text_str + kw_len + 1, value_len);
+                 value[value_len] = '\0';
+
+                 if (parse_real(value, NULL) == false && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                              errmsg("invalid input value for parameter %s: \"%s\"",
+                                     relOptBools[j].gen.name, value),
+                              errhint("value must be a float")));
+
+                 if ((value < relOptReals[j].min || value > relOptReals[j].max) && validate)
+                     ereport(ERROR,
+                             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                              errmsg("%s=%s is out of range (should be between %d and %d)",
+                                     relOptReals[j].gen.name, value, relOptReals[j].min, relOptReals[j].max)));
+
+                 values[j] = value;
+
+                 found = true;
+                 break;
+             }
+
+             j++;
+         }
+
          if (j >= numkeywords && validate)
          {
              char       *s;
***************
*** 276,281 ****
--- 583,591 ----
                       errmsg("unrecognized parameter \"%s\"", s)));
          }
      }
+
+     ereport(DEBUG2,
+             (errmsg("ending parseRelOptions() ...")));
  }


***************
*** 286,297 ****
  default_reloptions(Datum reloptions, bool validate,
                     int minFillfactor, int defaultFillfactor)
  {
-     static const char *const default_keywords[1] = {"fillfactor"};
      char       *values[1];
      int            fillfactor;
      StdRdOptions *result;

!     parseRelOptions(reloptions, 1, default_keywords, values, validate);

      /*
       * If no options, we can just return NULL rather than doing anything.
--- 596,609 ----
  default_reloptions(Datum reloptions, bool validate,
                     int minFillfactor, int defaultFillfactor)
  {
      char       *values[1];
      int            fillfactor;
      StdRdOptions *result;

!     ereport(DEBUG2,
!             (errmsg("starting default_options() ...")));
!
!     parseRelOptions(reloptions, values, validate, minFillfactor);

      /*
       * If no options, we can just return NULL rather than doing anything.
***************
*** 301,331 ****
      if (values[0] == NULL)
          return NULL;

-     if (!parse_int(values[0], &fillfactor, 0, NULL))
-     {
-         if (validate)
-             ereport(ERROR,
-                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                      errmsg("fillfactor must be an integer: \"%s\"",
-                             values[0])));
-         return NULL;
-     }
-
-     if (fillfactor < minFillfactor || fillfactor > 100)
-     {
-         if (validate)
-             ereport(ERROR,
-                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                      errmsg("fillfactor=%d is out of range (should be between %d and 100)",
-                             fillfactor, minFillfactor)));
-         return NULL;
-     }
-
      result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
      SET_VARSIZE(result, sizeof(StdRdOptions));

      result->fillfactor = fillfactor;

      return (bytea *) result;
  }

--- 613,626 ----
      if (values[0] == NULL)
          return NULL;

      result = (StdRdOptions *) palloc(sizeof(StdRdOptions));
      SET_VARSIZE(result, sizeof(StdRdOptions));

      result->fillfactor = fillfactor;

+     ereport(DEBUG2,
+             (errmsg("ending default_reloptions() ...")));
+
      return (bytea *) result;
  }

***************
*** 336,344 ****
  bytea *
  heap_reloptions(char relkind, Datum reloptions, bool validate)
  {
!     return default_reloptions(reloptions, validate,
!                               HEAP_MIN_FILLFACTOR,
!                               HEAP_DEFAULT_FILLFACTOR);
  }


--- 631,642 ----
  bytea *
  heap_reloptions(char relkind, Datum reloptions, bool validate)
  {
!     ereport(DEBUG2,
!             (errmsg("starting heap_reloptions() ...")));
!
!     return default_reloptions(reloptions, validate,
!                                 HEAP_MIN_FILLFACTOR,
!                                 HEAP_DEFAULT_FILLFACTOR);
  }


***************
*** 356,361 ****
--- 654,662 ----
      FunctionCallInfoData fcinfo;
      Datum        result;

+     ereport(DEBUG2,
+             (errmsg("starting index_reloptions() ...")));
+
      Assert(RegProcedureIsValid(amoptions));

      /* Assume function is strict */
***************
*** 377,381 ****
--- 678,685 ----
      if (fcinfo.isnull || DatumGetPointer(result) == NULL)
          return NULL;

+     ereport(DEBUG2,
+             (errmsg("ending index_reloptions() ...")));
+
      return DatumGetByteaP(result);
  }
Index: src/backend/access/gin/ginutil.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/gin/ginutil.c,v
retrieving revision 1.17
diff -c -r1.17 ginutil.c
*** src/backend/access/gin/ginutil.c    30 Sep 2008 10:52:10 -0000    1.17
--- src/backend/access/gin/ginutil.c    2 Oct 2008 20:33:13 -0000
***************
*** 339,347 ****
  #define GIN_MIN_FILLFACTOR            10
  #define GIN_DEFAULT_FILLFACTOR        100

!     result = default_reloptions(reloptions, validate,
!                                 GIN_MIN_FILLFACTOR,
                                  GIN_DEFAULT_FILLFACTOR);
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
--- 339,350 ----
  #define GIN_MIN_FILLFACTOR            10
  #define GIN_DEFAULT_FILLFACTOR        100

!     /* TODO how can we pass the min|default fillfactor to reloptions? */
!     /* XXX different AM has different values! */
!     result = default_reloptions(reloptions, validate,
!                                 GIN_MIN_FILLFACTOR,
                                  GIN_DEFAULT_FILLFACTOR);
+
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
Index: src/backend/access/gist/gistutil.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/gist/gistutil.c,v
retrieving revision 1.31
diff -c -r1.31 gistutil.c
*** src/backend/access/gist/gistutil.c    30 Sep 2008 10:52:10 -0000    1.31
--- src/backend/access/gist/gistutil.c    2 Oct 2008 20:33:28 -0000
***************
*** 670,678 ****
      bool        validate = PG_GETARG_BOOL(1);
      bytea       *result;

!     result = default_reloptions(reloptions, validate,
!                                 GIST_MIN_FILLFACTOR,
                                  GIST_DEFAULT_FILLFACTOR);
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
--- 670,681 ----
      bool        validate = PG_GETARG_BOOL(1);
      bytea       *result;

!     /* TODO how can we pass the min|default fillfactor to reloptions? */
!     /* XXX different AM has different values! */
!     result = default_reloptions(reloptions, validate,
!                                 GIST_MIN_FILLFACTOR,
                                  GIST_DEFAULT_FILLFACTOR);
+
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
Index: src/backend/access/hash/hashutil.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/hash/hashutil.c,v
retrieving revision 1.57
diff -c -r1.57 hashutil.c
*** src/backend/access/hash/hashutil.c    15 Sep 2008 18:43:41 -0000    1.57
--- src/backend/access/hash/hashutil.c    2 Oct 2008 20:32:48 -0000
***************
*** 224,232 ****
      bool        validate = PG_GETARG_BOOL(1);
      bytea       *result;

!     result = default_reloptions(reloptions, validate,
!                                 HASH_MIN_FILLFACTOR,
                                  HASH_DEFAULT_FILLFACTOR);
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
--- 224,235 ----
      bool        validate = PG_GETARG_BOOL(1);
      bytea       *result;

!     /* TODO how can we pass the min|default fillfactor to reloptions? */
!     /* XXX different AM has different values! */
!     result = default_reloptions(reloptions, validate,
!                                 HASH_MIN_FILLFACTOR,
                                  HASH_DEFAULT_FILLFACTOR);
+
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
Index: src/backend/access/nbtree/nbtutils.c
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/backend/access/nbtree/nbtutils.c,v
retrieving revision 1.91
diff -c -r1.91 nbtutils.c
*** src/backend/access/nbtree/nbtutils.c    19 Jun 2008 00:46:03 -0000    1.91
--- src/backend/access/nbtree/nbtutils.c    2 Oct 2008 20:32:35 -0000
***************
*** 1402,1410 ****
      bool        validate = PG_GETARG_BOOL(1);
      bytea       *result;

!     result = default_reloptions(reloptions, validate,
!                                 BTREE_MIN_FILLFACTOR,
                                  BTREE_DEFAULT_FILLFACTOR);
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
--- 1402,1413 ----
      bool        validate = PG_GETARG_BOOL(1);
      bytea       *result;

!     /* TODO how can we pass the min|default fillfactor to reloptions? */
!     /* XXX different AM has different values! */
!     result = default_reloptions(reloptions, validate,
!                                 BTREE_MIN_FILLFACTOR,
                                  BTREE_DEFAULT_FILLFACTOR);
+
      if (result)
          PG_RETURN_BYTEA_P(result);
      PG_RETURN_NULL();
Index: src/include/access/reloptions.h
===================================================================
RCS file: /a/pgsql/dev/anoncvs/pgsql/src/include/access/reloptions.h,v
retrieving revision 1.5
diff -c -r1.5 reloptions.h
*** src/include/access/reloptions.h    1 Jan 2008 19:45:56 -0000    1.5
--- src/include/access/reloptions.h    7 Oct 2008 04:57:59 -0000
***************
*** 20,36 ****

  #include "nodes/pg_list.h"

  extern Datum transformRelOptions(Datum oldOptions, List *defList,
                      bool ignoreOids, bool isReset);

  extern List *untransformRelOptions(Datum options);

! extern void parseRelOptions(Datum options, int numkeywords,
!                 const char *const * keywords,
!                 char **values, bool validate);

! extern bytea *default_reloptions(Datum reloptions, bool validate,
!                    int minFillfactor, int defaultFillfactor);

  extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);

--- 20,85 ----

  #include "nodes/pg_list.h"

+ /* types supported by reloptions */
+ enum ro_type
+ {
+     RO_BOOL,
+     RO_INT,
+     RO_REAL
+ };
+
+ /* kind supported by reloptions */
+ enum ro_kind
+ {
+     RO_INDEX,
+     RO_HEAP
+ };
+
+ /* generic struct to hold shared data */
+ struct relopt_gen
+ {
+     const char        *name;
+     const char        *desc;
+     enum ro_type    type;    /* type of variable */
+     enum ro_kind    kind;    /* index or heap? */
+ };
+
+ /* reloptions records for specific variable types */
+ struct relopt_bool
+ {
+     struct relopt_gen    gen;
+     bool                value;
+     bool                reset_value;    /* XXX useful? */
+ };
+
+ struct relopt_int
+ {
+     struct relopt_gen    gen;
+     int                    value;
+     int                    min;
+     int                    max;
+     int                    reset_value;    /* XXX useful? */
+ };
+
+ struct relopt_real
+ {
+     struct relopt_gen    gen;
+     double                value;
+     double                min;
+     double                max;
+     double                reset_value;    /* XXX useful? */
+ };
+
  extern Datum transformRelOptions(Datum oldOptions, List *defList,
                      bool ignoreOids, bool isReset);

  extern List *untransformRelOptions(Datum options);

! extern void parseRelOptions(Datum options, char **values, bool validate,
!                 int minFillfactor);

! extern bytea *default_reloptions(Datum reloptions, bool validate,
!                 int minFillfactor, int defaultFillfactor);

  extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);


В списке pgsql-hackers по дате отправления:

Предыдущее
От: ITAGAKI Takahiro
Дата:
Сообщение: Annoying error messages in _dosmaperr
Следующее
От: Simon Riggs
Дата:
Сообщение: Re: CLUSTER, REINDEX, VACUUM in "read only" transaction?