В письме от четверг, 4 июля 2019 г. 19:44:42 MSK пользователь Dent John 
написал:
> Hi Nikolay,
> 
> I have had a crack at re-basing the current patch against 12b2, but I didn’t
> trivially succeed.
> 
> It’s probably more my bodged fixing of the rejections than a fundamental
> problem. But I now get compile fails in — and seems like only — vacuum.c.

I am really sorry for such big delay. Two new relation options were added, it 
needed careful checking while importing them back to the patch.
I did not find proper timeslot for doing this quick enough.
Hope I am not terribly late.
Here goes an updated version.



diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 5773021..5483378 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -22,7 +22,7 @@
 #include "access/htup_details.h"
 #include "access/nbtree.h"
 #include "access/reloptions.h"
-#include "access/spgist.h"
+#include "access/spgist_private.h"
 #include "access/tuptoaster.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
@@ -46,9 +46,8 @@
  * upper and lower bounds (if applicable); for strings, consider a validation
  * routine.
  * (ii) add a record below (or use add_<type>_reloption).
- * (iii) add it to the appropriate options struct (perhaps StdRdOptions)
- * (iv) add it to the appropriate handling routine (perhaps
- * default_reloptions)
+ * (iii) add it to the appropriate options struct
+ * (iv) add it to the appropriate handling routine
  * (v) make sure the lock level is set correctly for that operation
  * (vi) don't forget to document the option
  *
@@ -1030,7 +1029,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
 		case RELKIND_TOASTVALUE:
 		case RELKIND_MATVIEW:
 		case RELKIND_PARTITIONED_TABLE:
-			options = heap_reloptions(classForm->relkind, datum, false);
+			options = relation_reloptions(classForm->relkind, datum, false);
 			break;
 		case RELKIND_VIEW:
 			options = view_reloptions(datum, false);
@@ -1363,67 +1362,73 @@ fillRelOptions(void *rdopts, Size basesize,
 
 
 /*
- * Option parser for anything that uses StdRdOptions.
+ * Option parsing definition for autovacuum. Used in toast and heap options.
+ */
+
+#define AUTOVACUUM_RELOPTIONS(OFFSET)                                \
+		{"autovacuum_enabled", RELOPT_TYPE_BOOL,                     \
+		OFFSET + offsetof(AutoVacOpts, enabled)},                    \
+		{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,             \
+		OFFSET + offsetof(AutoVacOpts, vacuum_threshold)},           \
+		{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,            \
+		OFFSET + offsetof(AutoVacOpts, analyze_threshold)},          \
+		{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,           \
+		OFFSET + offsetof(AutoVacOpts, vacuum_cost_delay)},          \
+		{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,            \
+		OFFSET + offsetof(AutoVacOpts, vacuum_cost_limit)},          \
+		{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,               \
+		OFFSET + offsetof(AutoVacOpts, freeze_min_age)},             \
+		{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,               \
+		OFFSET + offsetof(AutoVacOpts, freeze_max_age)},             \
+		{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,             \
+		OFFSET + offsetof(AutoVacOpts, freeze_table_age)},           \
+		{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,     \
+		OFFSET + offsetof(AutoVacOpts, multixact_freeze_min_age)},   \
+		{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,     \
+		OFFSET + offsetof(AutoVacOpts, multixact_freeze_max_age)},   \
+		{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,   \
+		OFFSET + offsetof(AutoVacOpts, multixact_freeze_table_age)}, \
+		{"log_autovacuum_min_duration", RELOPT_TYPE_INT,             \
+		OFFSET + offsetof(AutoVacOpts, log_min_duration)},           \
+		{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,         \
+		OFFSET + offsetof(AutoVacOpts, vacuum_scale_factor)},        \
+		{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,        \
+		OFFSET + offsetof(AutoVacOpts, analyze_scale_factor)}
+
+/*
+ * Option parser for heap
  */
 bytea *
-default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
+heap_reloptions(Datum reloptions, bool validate)
 {
 	relopt_value *options;
-	StdRdOptions *rdopts;
+	HeapRelOptions *rdopts;
 	int			numoptions;
 	static const relopt_parse_elt tab[] = {
-		{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
-		{"autovacuum_enabled", RELOPT_TYPE_BOOL,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
-		{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
-		{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
-		{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
-		{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
-		{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
-		{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
-		{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
-		{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
-		{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
-		{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
+		{"fillfactor", RELOPT_TYPE_INT, offsetof(HeapRelOptions, fillfactor)},
+		AUTOVACUUM_RELOPTIONS(offsetof(HeapRelOptions, autovacuum)),
 		{"toast_tuple_target", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, toast_tuple_target)},
-		{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
-		{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
-		{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
-		offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
+		offsetof(HeapRelOptions, toast_tuple_target)},
 		{"user_catalog_table", RELOPT_TYPE_BOOL,
-		offsetof(StdRdOptions, user_catalog_table)},
+		offsetof(HeapRelOptions, user_catalog_table)},
 		{"parallel_workers", RELOPT_TYPE_INT,
-		offsetof(StdRdOptions, parallel_workers)},
-		{"vacuum_cleanup_index_scale_factor", RELOPT_TYPE_REAL,
-		offsetof(StdRdOptions, vacuum_cleanup_index_scale_factor)},
+		offsetof(HeapRelOptions, parallel_workers)},
 		{"vacuum_index_cleanup", RELOPT_TYPE_BOOL,
-		offsetof(StdRdOptions, vacuum_index_cleanup)},
+		offsetof(HeapRelOptions, vacuum_index_cleanup)},
 		{"vacuum_truncate", RELOPT_TYPE_BOOL,
-		offsetof(StdRdOptions, vacuum_truncate)}
+		offsetof(HeapRelOptions, vacuum_truncate)}
 	};
 
-	options = parseRelOptions(reloptions, validate, kind, &numoptions);
+	options = parseRelOptions(reloptions, validate, RELOPT_KIND_HEAP,
+							  &numoptions);
 
 	/* if none set, we're done */
 	if (numoptions == 0)
 		return NULL;
 
-	rdopts = allocateReloptStruct(sizeof(StdRdOptions), options, numoptions);
+	rdopts = allocateReloptStruct(sizeof(HeapRelOptions), options, numoptions);
 
-	fillRelOptions((void *) rdopts, sizeof(StdRdOptions), options, numoptions,
+	fillRelOptions((void *) rdopts, sizeof(HeapRelOptions), options, numoptions,
 				   validate, tab, lengthof(tab));
 
 	pfree(options);
@@ -1432,6 +1437,64 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
 }
 
 /*
+ * Option parser for toast
+ */
+bytea *
+toast_reloptions(Datum reloptions, bool validate)
+{
+	relopt_value *options;
+	ToastRelOptions *rdopts;
+	int			numoptions;
+	static const relopt_parse_elt tab[] = {
+		AUTOVACUUM_RELOPTIONS(offsetof(ToastRelOptions, autovacuum)),
+		{"vacuum_index_cleanup", RELOPT_TYPE_BOOL,
+		offsetof(ToastRelOptions, vacuum_index_cleanup)},
+		{"vacuum_truncate", RELOPT_TYPE_BOOL,
+		offsetof(ToastRelOptions, vacuum_truncate)}
+	};
+
+	options = parseRelOptions(reloptions, validate, RELOPT_KIND_TOAST,
+							  &numoptions);
+
+	/* if none set, we're done */
+	if (numoptions == 0)
+		return NULL;
+
+	rdopts = allocateReloptStruct(sizeof(ToastRelOptions), options, numoptions);
+
+	fillRelOptions((void *) rdopts, sizeof(ToastRelOptions), options,
+				   numoptions, validate, tab, lengthof(tab));
+
+	/* adjust default-only parameters for TOAST relations */
+	rdopts->autovacuum.analyze_threshold = -1;
+	rdopts->autovacuum.analyze_scale_factor = -1;
+
+	pfree(options);
+
+	return (bytea *) rdopts;
+}
+
+/*
+ * Option parser for partitioned relations
+ */
+bytea *
+partitioned_reloptions(Datum reloptions, bool validate)
+{
+	int	  numoptions;
+
+  /*
+   * Since there is no options for patitioned table for now, we just do
+   * validation to report incorrect option error and leave.
+   */
+
+  if (validate)
+		parseRelOptions(reloptions, validate, RELOPT_KIND_PARTITIONED,
+						&numoptions);
+
+	return NULL;
+}
+
+/*
  * Option parser for views
  */
 bytea *
@@ -1464,39 +1527,26 @@ view_reloptions(Datum reloptions, bool validate)
 }
 
 /*
- * Parse options for heaps, views and toast tables.
+ * Parse options for heaps, toast, views and partitioned tables.
  */
 bytea *
-heap_reloptions(char relkind, Datum reloptions, bool validate)
+relation_reloptions(char relkind, Datum reloptions, bool validate)
 {
-	StdRdOptions *rdopts;
-
 	switch (relkind)
 	{
 		case RELKIND_TOASTVALUE:
-			rdopts = (StdRdOptions *)
-				default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
-			if (rdopts != NULL)
-			{
-				/* adjust default-only parameters for TOAST relations */
-				rdopts->fillfactor = 100;
-				rdopts->autovacuum.analyze_threshold = -1;
-				rdopts->autovacuum.analyze_scale_factor = -1;
-			}
-			return (bytea *) rdopts;
+			return toast_reloptions(reloptions, validate);
 		case RELKIND_RELATION:
 		case RELKIND_MATVIEW:
-			return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+			return heap_reloptions(reloptions, validate);
 		case RELKIND_PARTITIONED_TABLE:
-			return default_reloptions(reloptions, validate,
-									  RELOPT_KIND_PARTITIONED);
+			return partitioned_reloptions(reloptions, validate);
 		default:
 			/* other relkinds are not supported */
 			return NULL;
 	}
 }
 
-
 /*
  * Parse options for indexes.
  *
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 376ee2a..e8f933f 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -359,7 +359,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
 	data_width = sizeof(uint32);
 	item_width = MAXALIGN(sizeof(IndexTupleData)) + MAXALIGN(data_width) +
 		sizeof(ItemIdData);		/* include the line pointer */
-	ffactor = RelationGetTargetPageUsage(rel, HASH_DEFAULT_FILLFACTOR) / item_width;
+	ffactor = (BLCKSZ * HashGetFillFactor(rel) / 100) / item_width;
 	/* keep to a sane range */
 	if (ffactor < 10)
 		ffactor = 10;
diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c
index 3fb92ea..5170634 100644
--- a/src/backend/access/hash/hashutil.c
+++ b/src/backend/access/hash/hashutil.c
@@ -289,7 +289,28 @@ _hash_checkpage(Relation rel, Buffer buf, int flags)
 bytea *
 hashoptions(Datum reloptions, bool validate)
 {
-	return default_reloptions(reloptions, validate, RELOPT_KIND_HASH);
+	relopt_value *options;
+	HashRelOptions *rdopts;
+	int			numoptions;
+	static const relopt_parse_elt tab[] = {
+		{"fillfactor", RELOPT_TYPE_INT, offsetof(HashRelOptions, fillfactor)},
+	};
+
+	options = parseRelOptions(reloptions, validate, RELOPT_KIND_HASH,
+							  &numoptions);
+
+	/* if none set, we're done */
+	if (numoptions == 0)
+		return NULL;
+
+	rdopts = allocateReloptStruct(sizeof(HashRelOptions), options, numoptions);
+
+	fillRelOptions((void *) rdopts, sizeof(HashRelOptions), options, numoptions,
+				   validate, tab, lengthof(tab));
+
+	pfree(options);
+
+	return (bytea *) rdopts;
 }
 
 /*
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d768b9b..819176a 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2125,8 +2125,10 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
 	AssertArg(!(options & HEAP_INSERT_NO_LOGICAL));
 
 	needwal = !(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation);
-	saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
-												   HEAP_DEFAULT_FILLFACTOR);
+	if (IsToastRelation(relation))
+		saveFreeSpace = ToastGetTargetPageFreeSpace();
+	else
+		saveFreeSpace = HeapGetTargetPageFreeSpace(relation);
 
 	/* Toast and set header data in all the slots */
 	heaptuples = palloc(ntuples * sizeof(HeapTuple));
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index d41d318..dad8c0d 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -19,6 +19,7 @@
 #include "access/hio.h"
 #include "access/htup_details.h"
 #include "access/visibilitymap.h"
+#include "catalog/catalog.h"
 #include "storage/bufmgr.h"
 #include "storage/freespace.h"
 #include "storage/lmgr.h"
@@ -346,8 +347,10 @@ RelationGetBufferForTuple(Relation relation, Size len,
 						len, MaxHeapTupleSize)));
 
 	/* Compute desired extra freespace due to fillfactor option */
-	saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
-												   HEAP_DEFAULT_FILLFACTOR);
+	if (IsToastRelation(relation))
+		saveFreeSpace = ToastGetTargetPageFreeSpace();
+	else
+		saveFreeSpace = HeapGetTargetPageFreeSpace(relation);
 
 	if (otherBuffer != InvalidBuffer)
 		otherBlock = BufferGetBlockNumber(otherBuffer);
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index 0efe3ce..92240e3 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -129,8 +129,11 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
 	 * important than sometimes getting a wrong answer in what is after all
 	 * just a heuristic estimate.
 	 */
-	minfree = RelationGetTargetPageFreeSpace(relation,
-											 HEAP_DEFAULT_FILLFACTOR);
+
+	if (IsToastRelation(relation))
+		minfree = ToastGetTargetPageFreeSpace();
+	else
+		minfree = HeapGetTargetPageFreeSpace(relation);
 	minfree = Max(minfree, BLCKSZ / 10);
 
 	if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 72a448a..418d6b4 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -682,8 +682,10 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
 						len, MaxHeapTupleSize)));
 
 	/* Compute desired extra freespace due to fillfactor option */
-	saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel,
-												   HEAP_DEFAULT_FILLFACTOR);
+	if (IsToastRelation(state->rs_new_rel))
+		saveFreeSpace = ToastGetTargetPageFreeSpace();
+	else
+		saveFreeSpace = HeapGetTargetPageFreeSpace(state->rs_new_rel);
 
 	/* Now we can check to see if there's enough free space already. */
 	if (state->rs_buffer_valid)
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 4cfd528..b460d13 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -816,7 +816,7 @@ _bt_vacuum_needs_cleanup(IndexVacuumInfo *info)
 	}
 	else
 	{
-		StdRdOptions *relopts;
+		BTRelOptions *relopts;
 		float8		cleanup_scale_factor;
 		float8		prev_num_heap_tuples;
 
@@ -827,7 +827,7 @@ _bt_vacuum_needs_cleanup(IndexVacuumInfo *info)
 		 * tuples exceeds vacuum_cleanup_index_scale_factor fraction of
 		 * original tuples count.
 		 */
-		relopts = (StdRdOptions *) info->index->rd_options;
+		relopts = (BTRelOptions *) info->index->rd_options;
 		cleanup_scale_factor = (relopts &&
 								relopts->vacuum_cleanup_index_scale_factor >= 0)
 			? relopts->vacuum_cleanup_index_scale_factor
diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c
index d0b9013..6ba27ab 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -725,8 +725,9 @@ _bt_pagestate(BTWriteState *wstate, uint32 level)
 	if (level > 0)
 		state->btps_full = (BLCKSZ * (100 - BTREE_NONLEAF_FILLFACTOR) / 100);
 	else
-		state->btps_full = RelationGetTargetPageFreeSpace(wstate->index,
-														  BTREE_DEFAULT_FILLFACTOR);
+		state->btps_full = (BLCKSZ * (100 - BTGetFillFactor(wstate->index))
+							 / 100);
+
 	/* no parent level, yet */
 	state->btps_next = NULL;
 
diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c
index f43ec67..4ba82ab 100644
--- a/src/backend/access/nbtree/nbtsplitloc.c
+++ b/src/backend/access/nbtree/nbtsplitloc.c
@@ -167,7 +167,7 @@ _bt_findsplitloc(Relation rel,
 
 	/* Count up total space in data items before actually scanning 'em */
 	olddataitemstotal = rightspace - (int) PageGetExactFreeSpace(page);
-	leaffillfactor = RelationGetFillFactor(rel, BTREE_DEFAULT_FILLFACTOR);
+	leaffillfactor = BTGetFillFactor(rel);
 
 	/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
 	newitemsz += sizeof(ItemIdData);
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 93fab26..75b151a 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2027,7 +2027,31 @@ BTreeShmemInit(void)
 bytea *
 btoptions(Datum reloptions, bool validate)
 {
-	return default_reloptions(reloptions, validate, RELOPT_KIND_BTREE);
+	relopt_value *options;
+	BTRelOptions *rdopts;
+	int			numoptions;
+	static const relopt_parse_elt tab[] = {
+		{"fillfactor", RELOPT_TYPE_INT, offsetof(BTRelOptions, fillfactor)},
+		{"vacuum_cleanup_index_scale_factor", RELOPT_TYPE_REAL,
+		offsetof(BTRelOptions, vacuum_cleanup_index_scale_factor)}
+
+	};
+
+	options = parseRelOptions(reloptions, validate, RELOPT_KIND_BTREE,
+							  &numoptions);
+
+	/* if none set, we're done */
+	if (numoptions == 0)
+		return NULL;
+
+	rdopts = allocateReloptStruct(sizeof(BTRelOptions), options, numoptions);
+
+	fillRelOptions((void *) rdopts, sizeof(BTRelOptions), options, numoptions,
+				   validate, tab, lengthof(tab));
+
+	pfree(options);
+
+	return (bytea *) rdopts;
 }
 
 /*
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index 45472db..99dee1d 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -408,8 +408,7 @@ SpGistGetBuffer(Relation index, int flags, int needSpace, bool *isNew)
 	 * related to the ones already on it.  But fillfactor mustn't cause an
 	 * error for requests that would otherwise be legal.
 	 */
-	needSpace += RelationGetTargetPageFreeSpace(index,
-												SPGIST_DEFAULT_FILLFACTOR);
+	needSpace += (BLCKSZ * (100 - SpGistGetFillFactor(index)) / 100);
 	needSpace = Min(needSpace, SPGIST_PAGE_CAPACITY);
 
 	/* Get the cache entry for this flags setting */
@@ -586,7 +585,29 @@ SpGistInitMetapage(Page page)
 bytea *
 spgoptions(Datum reloptions, bool validate)
 {
-	return default_reloptions(reloptions, validate, RELOPT_KIND_SPGIST);
+	relopt_value       *options;
+	SpGistRelOptions   *rdopts;
+	int					numoptions;
+	static const relopt_parse_elt tab[] = {
+		{"fillfactor", RELOPT_TYPE_INT, offsetof(SpGistRelOptions, fillfactor)},
+	};
+
+	options = parseRelOptions(reloptions, validate, RELOPT_KIND_SPGIST,
+							  &numoptions);
+
+	/* if none set, we're done */
+	if (numoptions == 0)
+		return NULL;
+
+	rdopts = allocateReloptStruct(sizeof(SpGistRelOptions), options,
+									numoptions);
+
+	fillRelOptions((void *) rdopts, sizeof(SpGistRelOptions), options,
+					numoptions, validate, tab, lengthof(tab));
+
+	pfree(options);
+
+	return (bytea *) rdopts;
 }
 
 /*
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index 4c1d909..3e4f16e 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -131,7 +131,7 @@ create_ctas_internal(List *attrList, IntoClause *into)
 										validnsps,
 										true, false);
 
-	(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
+	(void) relation_reloptions(RELKIND_TOASTVALUE, toast_options, true);
 
 	NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 0f1a9f0..219ea50 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -722,7 +722,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	if (relkind == RELKIND_VIEW)
 		(void) view_reloptions(reloptions, true);
 	else
-		(void) heap_reloptions(relkind, reloptions, true);
+		(void) relation_reloptions(relkind, reloptions, true);
 
 	if (stmt->ofTypename)
 	{
@@ -12105,7 +12105,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 		case RELKIND_TOASTVALUE:
 		case RELKIND_MATVIEW:
 		case RELKIND_PARTITIONED_TABLE:
-			(void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
+			(void) relation_reloptions(rel->rd_rel->relkind, newOptions, true);
 			break;
 		case RELKIND_VIEW:
 			(void) view_reloptions(newOptions, true);
@@ -12214,7 +12214,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 										 defList, "toast", validnsps, false,
 										 operation == AT_ResetRelOptions);
 
-		(void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
+		(void) relation_reloptions(RELKIND_TOASTVALUE, newOptions, true);
 
 		memset(repl_val, 0, sizeof(repl_val));
 		memset(repl_null, false, sizeof(repl_null));
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index e7b379d..c0e4ff4 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -31,6 +31,7 @@
 #include "access/tableam.h"
 #include "access/transam.h"
 #include "access/xact.h"
+#include "catalog/catalog.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_inherits.h"
@@ -1758,7 +1759,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
 	if (params->index_cleanup == VACOPT_TERNARY_DEFAULT)
 	{
 		if (onerel->rd_options == NULL ||
-			((StdRdOptions *) onerel->rd_options)->vacuum_index_cleanup)
+			(!IsToastRelation(onerel) &&
+			 ((HeapRelOptions *) onerel->rd_options)->vacuum_index_cleanup) ||
+			(IsToastRelation(onerel) &&
+			 ((ToastRelOptions *) onerel->rd_options)->vacuum_index_cleanup))
 			params->index_cleanup = VACOPT_TERNARY_ENABLED;
 		else
 			params->index_cleanup = VACOPT_TERNARY_DISABLED;
@@ -1768,7 +1772,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
 	if (params->truncate == VACOPT_TERNARY_DEFAULT)
 	{
 		if (onerel->rd_options == NULL ||
-			((StdRdOptions *) onerel->rd_options)->vacuum_truncate)
+			(!IsToastRelation(onerel) &&
+			 ((HeapRelOptions *) onerel->rd_options)->vacuum_truncate) ||
+			(IsToastRelation(onerel) &&
+			 ((ToastRelOptions *) onerel->rd_options)->vacuum_truncate))
 			params->truncate = VACOPT_TERNARY_ENABLED;
 		else
 			params->truncate = VACOPT_TERNARY_DISABLED;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 40f4976..efa8fc3 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -148,8 +148,15 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 		estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
 						  &rel->pages, &rel->tuples, &rel->allvisfrac);
 
-	/* Retrieve the parallel_workers reloption, or -1 if not set. */
-	rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1);
+	/*
+	 * Retrieve the parallel_workers for heap and mat.view relations.
+	 * Use -1 if not set, or if we are dealing with other relation kinds
+	 */
+	if (relation->rd_rel->relkind == RELKIND_RELATION ||
+		relation->rd_rel->relkind == RELKIND_MATVIEW)
+		rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1);
+	else
+		rel->rel_parallel_workers = -1;
 
 	/*
 	 * Make list of indexes.  Ignore indexes on system catalogs if told to.
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 073f313..d111d4d 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2719,6 +2719,7 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
 {
 	bytea	   *relopts;
 	AutoVacOpts *av;
+	AutoVacOpts *src;
 
 	Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
 		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
@@ -2728,8 +2729,13 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
 	if (relopts == NULL)
 		return NULL;
 
+	if (((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE)
+		src = &(((ToastRelOptions *) relopts)->autovacuum);
+	else
+		src = &(((HeapRelOptions *) relopts)->autovacuum);
+
 	av = palloc(sizeof(AutoVacOpts));
-	memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
+	memcpy(av, src, sizeof(AutoVacOpts));
 	pfree(relopts);
 
 	return av;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 05ec7f3..67ed763 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1035,7 +1035,7 @@ ProcessUtilitySlow(ParseState *pstate,
 																validnsps,
 																true,
 																false);
-							(void) heap_reloptions(RELKIND_TOASTVALUE,
+							(void) relation_reloptions(RELKIND_TOASTVALUE,
 												   toast_options,
 												   true);
 
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 107c3d0..561ac3d 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -264,6 +264,17 @@ typedef struct HashMetaPageData
 
 typedef HashMetaPageData *HashMetaPage;
 
+typedef struct HashRelOptions
+{
+	int32		varlena_header_;  /* varlena header (do not touch directly!) */
+	int			fillfactor;		  /* page fill factor in percent (0..100) */
+}	HashRelOptions;
+
+#define HashGetFillFactor(relation) \
+	((relation)->rd_options ? \
+		((HashRelOptions *) (relation)->rd_options)->fillfactor : \
+		HASH_DEFAULT_FILLFACTOR)
+
 /*
  * Maximum size of a hash index item (it's okay to have only one per page)
  */
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index a3583f2..fcf7349 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -681,6 +681,19 @@ typedef BTScanOpaqueData *BTScanOpaque;
 #define SK_BT_DESC			(INDOPTION_DESC << SK_BT_INDOPTION_SHIFT)
 #define SK_BT_NULLS_FIRST	(INDOPTION_NULLS_FIRST << SK_BT_INDOPTION_SHIFT)
 
+typedef struct BTRelOptions
+{
+	int32	varlena_header_;	/* varlena header (do not touch directly!) */
+	int		fillfactor;			/* page fill factor in percent (0..100) */
+	/* fraction of newly inserted tuples prior to trigger index cleanup */
+	float8		vacuum_cleanup_index_scale_factor;
+}	BTRelOptions;
+
+#define BTGetFillFactor(relation) \
+	((relation)->rd_options ? \
+		((BTRelOptions *) (relation)->rd_options)->fillfactor : \
+		BTREE_DEFAULT_FILLFACTOR)
+
 /*
  * Constant definition for progress reporting.  Phase numbers must match
  * btbuildphasename.
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index a1912f4..bb85b31 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -270,9 +270,11 @@ extern void fillRelOptions(void *rdopts, Size basesize,
 						   bool validate,
 						   const relopt_parse_elt *elems, int nelems);
 
-extern bytea *default_reloptions(Datum reloptions, bool validate,
-								 relopt_kind kind);
-extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
+extern bytea *toast_reloptions(Datum reloptions, bool validate);
+extern bytea *partitioned_reloptions(Datum reloptions, bool validate);
+extern bytea *heap_reloptions(Datum reloptions, bool validate);
+extern bytea *relation_reloptions(char relkind, Datum reloptions,
+								  bool validate);
 extern bytea *view_reloptions(Datum reloptions, bool validate);
 extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
 							   bool validate);
diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h
index 02c8794..6eedaf9 100644
--- a/src/include/access/spgist.h
+++ b/src/include/access/spgist.h
@@ -20,10 +20,6 @@
 #include "lib/stringinfo.h"
 
 
-/* reloption parameters */
-#define SPGIST_MIN_FILLFACTOR			10
-#define SPGIST_DEFAULT_FILLFACTOR		80
-
 /* SPGiST opclass support function numbers */
 #define SPGIST_CONFIG_PROC				1
 #define SPGIST_CHOOSE_PROC				2
diff --git a/src/include/access/spgist_private.h b/src/include/access/spgist_private.h
index 4a38938..953bbdb 100644
--- a/src/include/access/spgist_private.h
+++ b/src/include/access/spgist_private.h
@@ -22,6 +22,17 @@
 #include "utils/relcache.h"
 
 
+typedef struct SpGistRelOptions
+{
+	int32		varlena_header_;  /* varlena header (do not touch directly!) */
+	int			fillfactor;		  /* page fill factor in percent (0..100) */
+}	SpGistRelOptions;
+
+#define SpGistGetFillFactor(relation) \
+	((relation)->rd_options ? \
+		((SpGistRelOptions *) (relation)->rd_options)->fillfactor : \
+		SPGIST_DEFAULT_FILLFACTOR)
+
 /* Page numbers of fixed-location pages */
 #define SPGIST_METAPAGE_BLKNO	 (0)	/* metapage */
 #define SPGIST_ROOT_BLKNO		 (1)	/* root for normal entries */
@@ -417,6 +428,11 @@ typedef SpGistDeadTupleData *SpGistDeadTuple;
 #define GBUF_REQ_NULLS(flags)	((flags) & GBUF_NULLS)
 
 /* spgutils.c */
+
+/* reloption parameters */
+#define SPGIST_MIN_FILLFACTOR			10
+#define SPGIST_DEFAULT_FILLFACTOR		80
+
 extern SpGistCache *spgGetCache(Relation index);
 extern void initSpGistState(SpGistState *state, Relation index);
 extern Buffer SpGistNewBuffer(Relation index);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index d35b4a5..6929636 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -231,15 +231,11 @@ typedef struct ForeignKeyCacheInfo
 } ForeignKeyCacheInfo;
 
 
+
 /*
- * StdRdOptions
- *		Standard contents of rd_options for heaps and generic indexes.
- *
- * RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only
- * be applied to relations that use this format or a superset for
- * private options data.
+ * AutoVacOpts
+ *		Auto Vacuum options used both in Heap and Toast relations
  */
- /* autovacuum-related reloptions. */
 typedef struct AutoVacOpts
 {
 	bool		enabled;
@@ -258,52 +254,86 @@ typedef struct AutoVacOpts
 	float8		analyze_scale_factor;
 } AutoVacOpts;
 
-typedef struct StdRdOptions
+/*
+ * HeapRelOptions
+ *		Binary representation of relation options for Heap relations.
+ */
+typedef struct HeapRelOptions
 {
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int			fillfactor;		/* page fill factor in percent (0..100) */
-	/* fraction of newly inserted tuples prior to trigger index cleanup */
-	float8		vacuum_cleanup_index_scale_factor;
 	int			toast_tuple_target; /* target for tuple toasting */
-	AutoVacOpts autovacuum;		/* autovacuum-related options */
+	AutoVacOpts autovacuum;	 		/* autovacuum-related options */
 	bool		user_catalog_table; /* use as an additional catalog relation */
 	int			parallel_workers;	/* max number of parallel workers */
-	bool		vacuum_index_cleanup;	/* enables index vacuuming and cleanup */
+	bool		vacuum_index_cleanup; /* enables index vacuuming and cleanup */
 	bool		vacuum_truncate;	/* enables vacuum to truncate a relation */
-} StdRdOptions;
+} HeapRelOptions;
+
+/*
+ * ToastRelOptions
+ *		Binary representation of relation options for Toast relations.
+ */
+typedef struct ToastRelOptions
+{
+	int32		vl_len_;		/* varlena header (do not touch directly!) */
+	AutoVacOpts autovacuum;		/* autovacuum-related options */
+	bool		vacuum_index_cleanup; /* enables index vacuuming and cleanup */
+	bool		vacuum_truncate;	/* enables vacuum to truncate a relation */
+} ToastRelOptions;
+
+
+/*
+ * PartitionedRelOptions
+ *		Binary representation of relation options for Partitioned relations.
+ */
+typedef struct PartitionedRelOptions
+{
+	int32		vl_len_;		/* varlena header (do not touch directly!) */
+	/* No options defined yet */
+} PartitionedRelOptions;
 
 #define HEAP_MIN_FILLFACTOR			10
 #define HEAP_DEFAULT_FILLFACTOR		100
 
+#define TOAST_DEFAULT_FILLFACTOR	100 /* Only default is actually used */
+
+
 /*
  * RelationGetToastTupleTarget
- *		Returns the relation's toast_tuple_target.  Note multiple eval of argument!
+ *		Returns the heap's toast_tuple_target.  Note multiple eval of argument!
  */
-#define RelationGetToastTupleTarget(relation, defaulttarg) \
-	((relation)->rd_options ? \
-	 ((StdRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
+#define RelationGetToastTupleTarget(relation, defaulttarg) 				\
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_RELATION ||		\
+				 relation->rd_rel->relkind == RELKIND_MATVIEW),			\
+	 ((relation)->rd_options ? 											\
+	  ((HeapRelOptions *) (relation)->rd_options)->toast_tuple_target : \
+			(defaulttarg)))
 
 /*
- * RelationGetFillFactor
- *		Returns the relation's fillfactor.  Note multiple eval of argument!
+ * HeapGetFillFactor
+ *		Returns the heap's fillfactor.  Note multiple eval of argument!
  */
-#define RelationGetFillFactor(relation, defaultff) \
-	((relation)->rd_options ? \
-	 ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
+#define HeapGetFillFactor(relation) 									\
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_RELATION ||		\
+				 relation->rd_rel->relkind == RELKIND_MATVIEW),			\
+	 ((relation)->rd_options ? 											\
+	  ((HeapRelOptions *) (relation)->rd_options)->fillfactor : 		\
+									(HEAP_DEFAULT_FILLFACTOR)))
 
 /*
- * RelationGetTargetPageUsage
- *		Returns the relation's desired space usage per page in bytes.
+ * HeapGetTargetPageUsage
+ *		Returns the heap's desired space usage per page in bytes.
  */
-#define RelationGetTargetPageUsage(relation, defaultff) \
-	(BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100)
+#define HeapGetTargetPageUsage(relation) \
+	(BLCKSZ * HeapGetFillFactor(relation) / 100)
 
 /*
- * RelationGetTargetPageFreeSpace
- *		Returns the relation's desired freespace per page in bytes.
+ * HeapGetTargetPageFreeSpace
+ *		Returns the heap's desired freespace per page in bytes.
  */
-#define RelationGetTargetPageFreeSpace(relation, defaultff) \
-	(BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100)
+#define HeapGetTargetPageFreeSpace(relation) \
+	(BLCKSZ * (100 - HeapGetFillFactor(relation)) / 100)
 
 /*
  * RelationIsUsedAsCatalogTable
@@ -314,17 +344,27 @@ typedef struct StdRdOptions
 	((relation)->rd_options && \
 	 ((relation)->rd_rel->relkind == RELKIND_RELATION || \
 	  (relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \
-	 ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false)
+	 ((HeapRelOptions *) (relation)->rd_options)->user_catalog_table : false)
 
 /*
  * RelationGetParallelWorkers
- *		Returns the relation's parallel_workers reloption setting.
+ *		Returns the heap's parallel_workers reloption setting.
  *		Note multiple eval of argument!
  */
-#define RelationGetParallelWorkers(relation, defaultpw) \
-	((relation)->rd_options ? \
-	 ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw))
+#define RelationGetParallelWorkers(relation, defaultpw) 				\
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_RELATION ||		\
+				 relation->rd_rel->relkind == RELKIND_MATVIEW),			\
+	 ((relation)->rd_options ? 											\
+	  ((HeapRelOptions *) (relation)->rd_options)->parallel_workers : 	\
+			(defaultpw)))
 
+/*
+ * ToastGetTargetPageFreeSpace
+ *		Returns the TOAST relation's desired freespace per page in bytes.
+ *		Always calculated using default fillfactor value.
+ */
+#define ToastGetTargetPageFreeSpace() \
+	(BLCKSZ * (100 - TOAST_DEFAULT_FILLFACTOR) / 100)
 
 /*
  * ViewOptions
@@ -342,9 +382,10 @@ typedef struct ViewOptions
  *		Returns whether the relation is security view, or not.  Note multiple
  *		eval of argument!
  */
-#define RelationIsSecurityView(relation)	\
-	((relation)->rd_options ?				\
-	 ((ViewOptions *) (relation)->rd_options)->security_barrier : false)
+#define RelationIsSecurityView(relation)									\
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW),				\
+	 ((relation)->rd_options ?												\
+	  ((ViewOptions *) (relation)->rd_options)->security_barrier : false))
 
 /*
  * RelationHasCheckOption
@@ -352,8 +393,9 @@ typedef struct ViewOptions
  *		or the cascaded check option.  Note multiple eval of argument!
  */
 #define RelationHasCheckOption(relation)									\
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW),				\
 	((relation)->rd_options &&												\
-	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0)
+	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0))
 
 /*
  * RelationHasLocalCheckOption
@@ -361,11 +403,12 @@ typedef struct ViewOptions
  *		option.  Note multiple eval of argument!
  */
 #define RelationHasLocalCheckOption(relation)								\
-	((relation)->rd_options &&												\
-	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ?	\
-	 strcmp((char *) (relation)->rd_options +								\
-			((ViewOptions *) (relation)->rd_options)->check_option_offset,	\
-			"local") == 0 : false)
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW),				\
+	 ((relation)->rd_options &&												\
+	  ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ?	\
+	   strcmp((char *) (relation)->rd_options +								\
+			 ((ViewOptions *) (relation)->rd_options)->check_option_offset,	\
+			 "local") == 0 : false))
 
 /*
  * RelationHasCascadedCheckOption
@@ -373,11 +416,12 @@ typedef struct ViewOptions
  *		option.  Note multiple eval of argument!
  */
 #define RelationHasCascadedCheckOption(relation)							\
+	(AssertMacro(relation->rd_rel->relkind == RELKIND_VIEW),				\
 	((relation)->rd_options &&												\
 	 ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0 ?	\
 	 strcmp((char *) (relation)->rd_options +								\
 			((ViewOptions *) (relation)->rd_options)->check_option_offset,	\
-			"cascaded") == 0 : false)
+			"cascaded") == 0 : false))
 
 
 /*

Reply via email to