В письме от четверг, 3 января 2019 г. 17:15:08 MSK пользователь Alvaro Herrera
написал:
> > Can we think about backward compatibility aliases?
.....
> > And keep them for as log as needed to avoid #if VERSION in thirdparty
> > code?
> Well, if you do this, at some point you need to tell the extension
> author to change the code. Or they can just keep the code unchanged
> forever. I don't think it's worth the bother.
Ok, you are the Boss ;-)
I've reverted all the macros names back to Relation* except those related to
fillfactor.
> I would have liked to get a StaticAssert in the definition, but I don't
> think it's possible. A standard Assert() should be possible, though.
This is a really good idea. I felt uncomfortable with this (ViewOptions *)
type convertation without checking that it is really View. With Assert I fell
much more safe.
I've added AssertMacro to all options related macroses.
And so, adding asserts discovered a bug with parallel_workers options. That
are defined as Heap only option, but in get_relation_info in src/backend/
optimizer/util/plancat.c a RelationGetParallelWorkers macros is also called
for toasts and other kinds of relations.
I've started a new thread dedicated to this issue, since it needs to be fixed
regardless to this patch.
And for now I added here a hotfix for this issue that is good enough for now.
I also reworked some comments. BTW do you know what is this comments spoke
about:
* RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only
* be applied to relations that use this format or a superset for
* private options data.
It is speaking about some old times when there can be some other type of
options? 'cause I do not understand what it is speaking about.
I've removed it, I hope I did not remove anything important.
diff --git a/.gitignore b/.gitignore
index 794e35b..2dfbbe1 100644
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index eece89a..833d084 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
*
@@ -1019,7 +1018,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);
@@ -1352,63 +1351,69 @@ 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_INT, \
+ 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_delay", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
- {"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_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)}
};
- 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);
@@ -1417,6 +1422,60 @@ 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)),
+ };
+
+ 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 *
@@ -1449,39 +1508,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 6825c14..e5a6dd8 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -369,7 +369,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 7c9b2cf..8cc1bd1 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 9650145..f60321d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2712,8 +2712,10 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, 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 tuples */
heaptuples = palloc(ntuples * sizeof(HeapTuple));
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index b8b5871..1574c0c 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"
@@ -339,8 +340,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 c2f5343..cc0b112 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -130,8 +130,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 44caeca..3c5b033 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -683,8 +683,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/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index a5915a5..c8b0af3 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -1607,8 +1607,7 @@ _bt_findsplitloc(Relation rel,
state.is_rightmost = P_RIGHTMOST(opaque);
state.have_split = false;
if (state.is_leaf)
- state.fillfactor = RelationGetFillFactor(rel,
- BTREE_DEFAULT_FILLFACTOR);
+ state.fillfactor = BTGetFillFactor(rel);
else
state.fillfactor = BTREE_NONLEAF_FILLFACTOR;
state.newitemonleft = false; /* these just to keep compiler quiet */
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index e8725fb..958b801 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -814,7 +814,7 @@ _bt_vacuum_needs_cleanup(IndexVacuumInfo *info)
}
else
{
- StdRdOptions *relopts;
+ BTRelOptions *relopts;
float8 cleanup_scale_factor;
float8 prev_num_heap_tuples;
@@ -825,7 +825,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 16f5755..f8c4fb4 100644
--- a/src/backend/access/nbtree/nbtsort.c
+++ b/src/backend/access/nbtree/nbtsort.c
@@ -681,8 +681,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/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 205457e..11a1de3 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -2053,7 +2053,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 9919e6f..44bdc5b 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -411,8 +411,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 */
@@ -589,7 +588,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 d01b258..d54f9e4 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -128,7 +128,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 c8c50e8..93918cc 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -685,7 +685,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)
{
@@ -10674,7 +10674,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);
@@ -10783,7 +10783,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/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 5790b62..a9e5e59 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -146,7 +146,24 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
&rel->pages, &rel->tuples, &rel->allvisfrac);
/* Retrieve the parallel_workers reloption, or -1 if not set. */
- rel->rel_parallel_workers = RelationGetParallelWorkers(relation, -1);
+
+ switch (relation->rd_rel->relkind)
+ {
+ case RELKIND_RELATION:
+ case RELKIND_MATVIEW:
+ rel->rel_parallel_workers =
+ RelationGetParallelWorkers(relation,-1);
+ break;
+ case RELKIND_TOASTVALUE:
+ case RELKIND_PARTITIONED_TABLE:
+ case RELKIND_SEQUENCE:
+ case REPLICA_IDENTITY_FULL: /* Foreign table */
+ rel->rel_parallel_workers = -1;
+ break;
+ default:
+ /* Other relkinds are not supported */
+ Assert(false);
+ }
/*
* 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 2d5086d..b605edd 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2720,6 +2720,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 ||
@@ -2729,8 +2730,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 970c94e..1b28a6a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1024,7 +1024,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 02ef67c..e6b9208 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -274,6 +274,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 ea495f1..d7066d0 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -488,6 +488,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)
+
/*
* external entry points for btree, in nbtree.c
*/
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 50690b9..6d309b3 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -271,9 +271,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 9c19e9e..4c57a0a 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 d23862e..a567603 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 2217081..47f6dd9 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -226,15 +226,11 @@ typedef struct GenericIndexOpts
bool recheck_on_update;
} GenericIndexOpts;
+
/*
- * 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;
@@ -253,50 +249,88 @@ 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 */
-} 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 */
+} 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 */
+
+
+/*
+ * IsHeapRelation
+ * Returns true if relation is a Heap Relation or a Materialized View.
+ */
+#define IsHeapRelation(relation) \
+ (relation->rd_rel->relkind == RELKIND_RELATION || \
+ relation->rd_rel->relkind == RELKIND_MATVIEW)
+
/*
* 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(IsHeapRelation(relation)), \
+ ((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(IsHeapRelation(relation)), \
+ ((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
@@ -307,17 +341,26 @@ 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(IsHeapRelation(relation)), \
+ ((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
@@ -330,14 +373,23 @@ typedef struct ViewOptions
int check_option_offset;
} ViewOptions;
+
+/*
+ * IsViewRelation
+ * Returnt ture if relation is a View Relation
+ */
+#define IsViewRelation(relation) \
+ (relation->rd_rel->relkind == RELKIND_VIEW)
+
/*
* RelationIsSecurityView
* 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)
+ (AssertMacro(IsViewRelation(relation)), \
+ ((relation)->rd_options ? \
+ ((ViewOptions *) (relation)->rd_options)->security_barrier : false))
/*
* RelationHasCheckOption
@@ -345,8 +397,9 @@ typedef struct ViewOptions
* or the cascaded check option. Note multiple eval of argument!
*/
#define RelationHasCheckOption(relation) \
+ (AssertMacro(IsViewRelation(relation)), \
((relation)->rd_options && \
- ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0)
+ ((ViewOptions *) (relation)->rd_options)->check_option_offset != 0))
/*
* RelationHasLocalCheckOption
@@ -354,11 +407,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(IsViewRelation(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))
/*
* RelationHasCascadedCheckOption
@@ -366,11 +420,12 @@ typedef struct ViewOptions
* option. Note multiple eval of argument!
*/
#define RelationHasCascadedCheckOption(relation) \
+ (AssertMacro(IsViewRelation(relation)), \
((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))
/*