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);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers