v11-0001-Custom-reloptions-for-table-AM.patch
application/octet-stream
Filename: v11-0001-Custom-reloptions-for-table-AM.patch
Type: application/octet-stream
Part: 0
Message:
Re: Table AM Interface Enhancements
Patch
Format: format-patch
Series: patch v11-0001
Subject: Custom reloptions for table AM
| File | + | − |
|---|---|---|
| src/backend/access/common/reloptions.c | 86 | 35 |
| src/backend/access/heap/heapam.c | 2 | 2 |
| src/backend/access/heap/heapam_handler.c | 13 | 0 |
| src/backend/access/heap/heaptoast.c | 8 | 1 |
| src/backend/access/heap/hio.c | 2 | 2 |
| src/backend/access/heap/pruneheap.c | 2 | 2 |
| src/backend/access/heap/rewriteheap.c | 2 | 2 |
| src/backend/access/table/tableamapi.c | 25 | 0 |
| src/backend/access/table/tableam.c | 1 | 1 |
| src/backend/commands/createas.c | 12 | 1 |
| src/backend/commands/tablecmds.c | 38 | 25 |
| src/backend/commands/vacuum.c | 3 | 7 |
| src/backend/optimizer/util/plancat.c | 1 | 1 |
| src/backend/postmaster/autovacuum.c | 7 | 5 |
| src/backend/tcop/utility.c | 17 | 3 |
| src/backend/utils/cache/relcache.c | 32 | 1 |
| src/include/access/reloptions.h | 6 | 4 |
| src/include/access/tableam.h | 51 | 1 |
| src/include/utils/rel.h | 77 | 71 |
| src/test/modules/Makefile | 1 | 0 |
| src/test/modules/meson.build | 1 | 0 |
| src/test/modules/test_tam_options/expected/test_tam_options.out | 36 | 0 |
| src/test/modules/test_tam_options/.gitignore | 4 | 0 |
| src/test/modules/test_tam_options/Makefile | 23 | 0 |
| src/test/modules/test_tam_options/meson.build | 33 | 0 |
| src/test/modules/test_tam_options/sql/test_tam_options.sql | 25 | 0 |
| src/test/modules/test_tam_options/test_tam_options--1.0.sql | 12 | 0 |
| src/test/modules/test_tam_options/test_tam_options.c | 66 | 0 |
| src/test/modules/test_tam_options/test_tam_options.control | 4 | 0 |
| src/tools/pgindent/typedefs.list | 2 | 1 |
From 30890f0f11070376631db2bb3a7d96aa30209da8 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Sat, 6 Apr 2024 14:01:50 +0300
Subject: [PATCH v11] Custom reloptions for table AM
Let table AM define custom reloptions for its tables. This allows specifying
AM-specific parameters by the WITH clause when creating a table.
The reloptions, which could be used outside of table AM, are now extracted
into the CommonRdOptions data structure. These options could be by decision
of table AM directly specified by a user or calculated in some way.
The new test module test_tam_options evaluates the ability to set up custom
reloptions and calculate fields of CommonRdOptions on their base.
The code may use some parts from prior work by Hao Wu.
Discussion: https://postgr.es/m/CAPpHfdurb9ycV8udYqM%3Do0sPS66PJ4RCBM1g-bBpvzUfogY0EA%40mail.gmail.com
Discussion: https://postgr.es/m/AMUA1wBBBxfc3tKRLLdU64rb.1.1683276279979.Hmail.wuhao%40hashdata.cn
Reviewed-by: Reviewed-by: Pavel Borisov, Matthias van de Meent, Jess Davis
---
src/backend/access/common/reloptions.c | 121 +++++++++-----
src/backend/access/heap/heapam.c | 4 +-
src/backend/access/heap/heapam_handler.c | 13 ++
src/backend/access/heap/heaptoast.c | 9 +-
src/backend/access/heap/hio.c | 4 +-
src/backend/access/heap/pruneheap.c | 4 +-
src/backend/access/heap/rewriteheap.c | 4 +-
src/backend/access/table/tableam.c | 2 +-
src/backend/access/table/tableamapi.c | 25 +++
src/backend/commands/createas.c | 13 +-
src/backend/commands/tablecmds.c | 63 +++++---
src/backend/commands/vacuum.c | 10 +-
src/backend/optimizer/util/plancat.c | 2 +-
src/backend/postmaster/autovacuum.c | 12 +-
src/backend/tcop/utility.c | 20 ++-
src/backend/utils/cache/relcache.c | 33 +++-
src/include/access/reloptions.h | 10 +-
src/include/access/tableam.h | 52 +++++-
src/include/utils/rel.h | 148 +++++++++---------
src/test/modules/Makefile | 1 +
src/test/modules/meson.build | 1 +
src/test/modules/test_tam_options/.gitignore | 4 +
src/test/modules/test_tam_options/Makefile | 23 +++
.../expected/test_tam_options.out | 36 +++++
src/test/modules/test_tam_options/meson.build | 33 ++++
.../test_tam_options/sql/test_tam_options.sql | 25 +++
.../test_tam_options--1.0.sql | 12 ++
.../test_tam_options/test_tam_options.c | 66 ++++++++
.../test_tam_options/test_tam_options.control | 4 +
src/tools/pgindent/typedefs.list | 3 +-
30 files changed, 592 insertions(+), 165 deletions(-)
create mode 100644 src/test/modules/test_tam_options/.gitignore
create mode 100644 src/test/modules/test_tam_options/Makefile
create mode 100644 src/test/modules/test_tam_options/expected/test_tam_options.out
create mode 100644 src/test/modules/test_tam_options/meson.build
create mode 100644 src/test/modules/test_tam_options/sql/test_tam_options.sql
create mode 100644 src/test/modules/test_tam_options/test_tam_options--1.0.sql
create mode 100644 src/test/modules/test_tam_options/test_tam_options.c
create mode 100644 src/test/modules/test_tam_options/test_tam_options.control
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index d6eb5d8559..c1de092a42 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -24,6 +24,7 @@
#include "access/nbtree.h"
#include "access/reloptions.h"
#include "access/spgist_private.h"
+#include "access/tableam.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "commands/tablespace.h"
@@ -44,7 +45,7 @@
* value, 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)
+ * (iii) add it to the appropriate options struct (perhaps HeapRdOptions)
* (iv) add it to the appropriate handling routine (perhaps
* default_reloptions)
* (v) make sure the lock level is set correctly for that operation
@@ -1374,10 +1375,16 @@ untransformRelOptions(Datum options)
* tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
* AM's options parser function in the case of a tuple corresponding to an
* index, or NULL otherwise.
+ *
+ * If common pointer is provided, then the corresponding struct will be
+ * filled with options that table AM exposes for external usage. That must
+ * be filled with defaults before passing here.
*/
+
bytea *
extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
- amoptions_function amoptions)
+ const TableAmRoutine *tableam, amoptions_function amoptions,
+ CommonRdOptions *common)
{
bytea *options;
bool isnull;
@@ -1399,7 +1406,8 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- options = heap_reloptions(classForm->relkind, datum, false);
+ options = tableam_reloptions(tableam, classForm->relkind,
+ datum, common, false);
break;
case RELKIND_PARTITIONED_TABLE:
options = partitioned_table_reloptions(datum, false);
@@ -1695,7 +1703,7 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
* Given the result from parseRelOptions, allocate a struct that's of the
* specified base size plus any extra space that's needed for string variables.
*
- * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
+ * "base" should be sizeof(struct) of the reloptions struct (HeapRdOptions or
* equivalent).
*/
static void *
@@ -1832,59 +1840,95 @@ fillRelOptions(void *rdopts, Size basesize,
/*
- * Option parser for anything that uses StdRdOptions.
+ * Option parser for anything that uses HeapRdOptions.
*/
-bytea *
+static bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{
static const relopt_parse_elt tab[] = {
- {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
+ {"fillfactor", RELOPT_TYPE_INT, offsetof(HeapRdOptions, fillfactor)},
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, enabled)},
{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, vacuum_threshold)},
{"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, vacuum_ins_threshold)},
{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, analyze_threshold)},
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, vacuum_cost_limit)},
{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, freeze_min_age)},
{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, freeze_max_age)},
{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, freeze_table_age)},
{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, multixact_freeze_min_age)},
{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, multixact_freeze_max_age)},
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, multixact_freeze_table_age)},
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, log_min_duration)},
{"toast_tuple_target", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, toast_tuple_target)},
+ offsetof(HeapRdOptions, toast_tuple_target)},
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, vacuum_cost_delay)},
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, vacuum_scale_factor)},
{"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
- offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, autovacuum) +
+ offsetof(AutoVacOpts, analyze_scale_factor)},
{"user_catalog_table", RELOPT_TYPE_BOOL,
- offsetof(StdRdOptions, user_catalog_table)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, user_catalog_table)},
{"parallel_workers", RELOPT_TYPE_INT,
- offsetof(StdRdOptions, parallel_workers)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, parallel_workers)},
{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
- offsetof(StdRdOptions, vacuum_index_cleanup)},
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, vacuum_index_cleanup)},
{"vacuum_truncate", RELOPT_TYPE_BOOL,
- offsetof(StdRdOptions, vacuum_truncate)}
+ offsetof(HeapRdOptions, common) +
+ offsetof(CommonRdOptions, vacuum_truncate)}
};
return (bytea *) build_reloptions(reloptions, validate, kind,
- sizeof(StdRdOptions),
+ sizeof(HeapRdOptions),
tab, lengthof(tab));
}
@@ -2016,26 +2060,33 @@ view_reloptions(Datum reloptions, bool validate)
* Parse options for heaps, views and toast tables.
*/
bytea *
-heap_reloptions(char relkind, Datum reloptions, bool validate)
+heap_reloptions(char relkind, Datum reloptions,
+ CommonRdOptions *common, bool validate)
{
- StdRdOptions *rdopts;
+ HeapRdOptions *rdopts;
switch (relkind)
{
case RELKIND_TOASTVALUE:
- rdopts = (StdRdOptions *)
+ rdopts = (HeapRdOptions *)
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;
+ rdopts->common.autovacuum.analyze_threshold = -1;
+ rdopts->common.autovacuum.analyze_scale_factor = -1;
}
+ if (rdopts != NULL && common != NULL)
+ *common = rdopts->common;
return (bytea *) rdopts;
case RELKIND_RELATION:
case RELKIND_MATVIEW:
- return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+ rdopts = (HeapRdOptions *)
+ default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
+ if (rdopts != NULL && common != NULL)
+ *common = rdopts->common;
+ return (bytea *) rdopts;
default:
/* other relkinds are not supported */
return NULL;
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 2663f52d1a..087bb63d1b 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2279,8 +2279,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
Assert(!(options & HEAP_INSERT_NO_LOGICAL));
needwal = RelationNeedsWAL(relation);
- saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
- HEAP_DEFAULT_FILLFACTOR);
+ saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
+ HEAP_DEFAULT_FILLFACTOR);
/* Toast and set header data in all the slots */
heaptuples = palloc(ntuples * sizeof(HeapTuple));
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 58de2c82a7..4f20522fa9 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -23,6 +23,7 @@
#include "access/heapam.h"
#include "access/heaptoast.h"
#include "access/multixact.h"
+#include "access/reloptions.h"
#include "access/rewriteheap.h"
#include "access/syncscan.h"
#include "access/tableam.h"
@@ -2158,6 +2159,17 @@ heapam_relation_toast_am(Relation rel)
return rel->rd_rel->relam;
}
+static bytea *
+heapam_reloptions(char relkind, Datum reloptions,
+ CommonRdOptions *common, bool validate)
+{
+ Assert(relkind == RELKIND_RELATION ||
+ relkind == RELKIND_TOASTVALUE ||
+ relkind == RELKIND_MATVIEW);
+
+ return heap_reloptions(relkind, reloptions, common, validate);
+}
+
/* ------------------------------------------------------------------------
* Planner related callbacks for the heap AM
@@ -2707,6 +2719,7 @@ static const TableAmRoutine heapam_methods = {
.relation_needs_toast_table = heapam_relation_needs_toast_table,
.relation_toast_am = heapam_relation_toast_am,
.relation_fetch_toast_slice = heap_fetch_toast_slice,
+ .reloptions = heapam_reloptions,
.relation_estimate_size = heapam_estimate_rel_size,
diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c
index a420e16530..cffee7e1b7 100644
--- a/src/backend/access/heap/heaptoast.c
+++ b/src/backend/access/heap/heaptoast.c
@@ -32,6 +32,13 @@
#include "access/toast_internals.h"
#include "utils/fmgroids.h"
+/*
+ * HeapGetToastTupleTarget
+ * Returns the heap relation's toast_tuple_target. Note multiple eval of argument!
+ */
+#define HeapGetToastTupleTarget(relation, defaulttarg) \
+ ((HeapRdOptions *) (relation)->rd_options ? \
+ ((HeapRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
/* ----------
* heap_toast_delete -
@@ -174,7 +181,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
hoff += BITMAPLEN(numAttrs);
hoff = MAXALIGN(hoff);
/* now convert to a limit on the tuple data size */
- maxDataLen = RelationGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
+ maxDataLen = HeapGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
/*
* Look for attributes with attstorage EXTENDED to compress. Also find
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 7c662cdf46..ed731179b4 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -536,8 +536,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
len, MaxHeapTupleSize)));
/* Compute desired extra freespace due to fillfactor option */
- saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
- HEAP_DEFAULT_FILLFACTOR);
+ saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
+ HEAP_DEFAULT_FILLFACTOR);
/*
* Since pages without tuples can still have line pointers, we consider
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index d2eecaf7eb..20142dd214 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -235,8 +235,8 @@ 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);
+ minfree = HeapGetTargetPageFreeSpace(relation,
+ HEAP_DEFAULT_FILLFACTOR);
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 473f3aa9be..2bbf121146 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -641,8 +641,8 @@ 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);
+ saveFreeSpace = HeapGetTargetPageFreeSpace(state->rs_new_rel,
+ HEAP_DEFAULT_FILLFACTOR);
/* Now we can check to see if there's enough free space already. */
page = (Page) state->rs_buffer;
diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c
index 805d222ceb..5d5f0e68fd 100644
--- a/src/backend/access/table/tableam.c
+++ b/src/backend/access/table/tableam.c
@@ -750,7 +750,7 @@ table_block_relation_estimate_size(Relation rel, int32 *attr_widths,
* The other branch considers it implicitly by calculating density
* from actual relpages/reltuples statistics.
*/
- fillfactor = RelationGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
+ fillfactor = HeapGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
tuple_width = get_rel_data_width(rel, attr_widths);
tuple_width += overhead_bytes_per_tuple;
diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c
index 55b8caeadf..d9e23ef317 100644
--- a/src/backend/access/table/tableamapi.c
+++ b/src/backend/access/table/tableamapi.c
@@ -13,9 +13,11 @@
#include "access/tableam.h"
#include "access/xact.h"
+#include "catalog/pg_am.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "utils/guc_hooks.h"
+#include "utils/syscache.h"
/*
@@ -98,6 +100,29 @@ GetTableAmRoutine(Oid amhandler)
return routine;
}
+/*
+ * GetTableAmRoutineByAmOid
+ * Given the table access method oid get its TableAmRoutine struct, which
+ * will be palloc'd in the caller's memory context.
+ */
+const TableAmRoutine *
+GetTableAmRoutineByAmOid(Oid amoid)
+{
+ HeapTuple ht_am;
+ Form_pg_am amrec;
+ const TableAmRoutine *tableam = NULL;
+
+ ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(ht_am))
+ elog(ERROR, "cache lookup failed for access method %u",
+ amoid);
+ amrec = (Form_pg_am) GETSTRUCT(ht_am);
+
+ tableam = GetTableAmRoutine(amrec->amhandler);
+ ReleaseSysCache(ht_am);
+ return tableam;
+}
+
/* check_hook: validate new default_table_access_method */
bool
check_default_table_access_method(char **newval, void **extra, GucSource source)
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index afd3dace07..c5df96e374 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -85,6 +85,9 @@ create_ctas_internal(List *attrList, IntoClause *into)
Datum toast_options;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
ObjectAddress intoRelationAddr;
+ const TableAmRoutine *tableam = NULL;
+ Oid accessMethodId = InvalidOid;
+ Relation rel;
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
is_matview = (into->viewQuery != NULL);
@@ -125,7 +128,15 @@ create_ctas_internal(List *attrList, IntoClause *into)
validnsps,
true, false);
- (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
+ rel = relation_open(intoRelationAddr.objectId, AccessShareLock);
+ accessMethodId = table_relation_toast_am(rel);
+ relation_close(rel, AccessShareLock);
+
+ if (OidIsValid(accessMethodId))
+ {
+ tableam = GetTableAmRoutineByAmOid(accessMethodId);
+ (void) tableam_reloptions(tableam, RELKIND_TOASTVALUE, toast_options, NULL, true);
+ }
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 582890a302..3c74eef3e6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -720,6 +720,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
ObjectAddress address;
LOCKMODE parentLockmode;
Oid accessMethodId = InvalidOid;
+ const TableAmRoutine *tableam = NULL;
/*
* Truncate relname to appropriate length (probably a waste of time, as
@@ -855,6 +856,28 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
if (!OidIsValid(ownerId))
ownerId = GetUserId();
+ /*
+ * For relations with table AM and partitioned tables, select access
+ * method to use: an explicitly indicated one, or (in the case of a
+ * partitioned table) the parent's, if it has one.
+ */
+ if (stmt->accessMethod != NULL)
+ {
+ Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
+ accessMethodId = get_table_am_oid(stmt->accessMethod, false);
+ }
+ else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ if (stmt->partbound)
+ {
+ Assert(list_length(inheritOids) == 1);
+ accessMethodId = get_rel_relam(linitial_oid(inheritOids));
+ }
+
+ if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
+ accessMethodId = get_table_am_oid(default_table_access_method, false);
+ }
+
/*
* Parse and validate reloptions, if any.
*/
@@ -863,6 +886,12 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
switch (relkind)
{
+ case RELKIND_RELATION:
+ case RELKIND_TOASTVALUE:
+ case RELKIND_MATVIEW:
+ tableam = GetTableAmRoutineByAmOid(accessMethodId);
+ (void) tableam_reloptions(tableam, relkind, reloptions, NULL, true);
+ break;
case RELKIND_VIEW:
(void) view_reloptions(reloptions, true);
break;
@@ -870,7 +899,12 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
(void) partitioned_table_reloptions(reloptions, true);
break;
default:
- (void) heap_reloptions(relkind, reloptions, true);
+ if (OidIsValid(accessMethodId))
+ {
+ tableam = GetTableAmRoutineByAmOid(accessMethodId);
+ (void) tableam_reloptions(tableam, relkind, reloptions, NULL, true);
+ }
+ break;
}
if (stmt->ofTypename)
@@ -962,28 +996,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
}
}
- /*
- * For relations with table AM and partitioned tables, select access
- * method to use: an explicitly indicated one, or (in the case of a
- * partitioned table) the parent's, if it has one.
- */
- if (stmt->accessMethod != NULL)
- {
- Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
- accessMethodId = get_table_am_oid(stmt->accessMethod, false);
- }
- else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
- {
- if (stmt->partbound)
- {
- Assert(list_length(inheritOids) == 1);
- accessMethodId = get_rel_relam(linitial_oid(inheritOids));
- }
-
- if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
- accessMethodId = get_table_am_oid(default_table_access_method, false);
- }
-
/*
* Create the relation. Inherited defaults and constraints are passed in
* for immediate handling --- since they don't need parsing, they can be
@@ -15571,7 +15583,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_MATVIEW:
- (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true);
+ (void) table_reloptions(rel, rel->rd_rel->relkind,
+ newOptions, NULL, true);
break;
case RELKIND_PARTITIONED_TABLE:
(void) partitioned_table_reloptions(newOptions, true);
@@ -15684,7 +15697,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
defList, "toast", validnsps, false,
operation == AT_ResetRelOptions);
- (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true);
+ (void) table_reloptions(rel, RELKIND_TOASTVALUE, newOptions, NULL, 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 b589279d49..ba13fc0ad6 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -2121,11 +2121,8 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
{
StdRdOptIndexCleanup vacuum_index_cleanup;
- if (rel->rd_options == NULL)
- vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
- else
- vacuum_index_cleanup =
- ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup;
+ vacuum_index_cleanup =
+ rel->rd_common_options.vacuum_index_cleanup;
if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO)
params->index_cleanup = VACOPTVALUE_AUTO;
@@ -2145,8 +2142,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
*/
if (params->truncate == VACOPTVALUE_UNSPECIFIED)
{
- if (rel->rd_options == NULL ||
- ((StdRdOptions *) rel->rd_options)->vacuum_truncate)
+ if (rel->rd_common_options.vacuum_truncate)
params->truncate = VACOPTVALUE_ENABLED;
else
params->truncate = VACOPTVALUE_DISABLED;
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 6bb53e4346..bea4440f71 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -190,7 +190,7 @@ 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);
+ rel->rel_parallel_workers = RelationGetParallelWorkers(relation);
/*
* 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 c367ede6f8..7cb79ebced 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2674,19 +2674,21 @@ static AutoVacOpts *
extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
{
bytea *relopts;
+ CommonRdOptions common;
AutoVacOpts *av;
Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
- if (relopts == NULL)
- return NULL;
+ relopts = extractRelOptions(tup, pg_class_desc,
+ GetTableAmRoutineByAmOid(((Form_pg_class) GETSTRUCT(tup))->relam),
+ NULL, &common);
+ if (relopts)
+ pfree(relopts);
av = palloc(sizeof(AutoVacOpts));
- memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
- pfree(relopts);
+ memcpy(av, &(common.autovacuum), sizeof(AutoVacOpts));
return av;
}
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index fa66b8017e..abdd94ad95 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -65,6 +65,7 @@
#include "utils/acl.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
+#include "access/relation.h"
/* Hook for plugins to get control in ProcessUtility() */
ProcessUtility_hook_type ProcessUtility_hook = NULL;
@@ -1156,6 +1157,9 @@ ProcessUtilitySlow(ParseState *pstate,
CreateStmt *cstmt = (CreateStmt *) stmt;
Datum toast_options;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
+ const TableAmRoutine *tableam = NULL;
+ Oid accessMethodId;
+ Relation rel;
/* Remember transformed RangeVar for LIKE */
table_rv = cstmt->relation;
@@ -1185,9 +1189,19 @@ ProcessUtilitySlow(ParseState *pstate,
validnsps,
true,
false);
- (void) heap_reloptions(RELKIND_TOASTVALUE,
- toast_options,
- true);
+
+ rel = relation_open(address.objectId, AccessShareLock);
+ accessMethodId = table_relation_toast_am(rel);
+ relation_close(rel, AccessShareLock);
+
+ if (OidIsValid(accessMethodId))
+ {
+ tableam = GetTableAmRoutineByAmOid(accessMethodId);
+ (void) tableam_reloptions(tableam, RELKIND_TOASTVALUE,
+ toast_options,
+ NULL,
+ true);
+ }
NewRelationCreateToastTable(address.objectId,
toast_options);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 3fe74dabd0..0e3b4cc93f 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -33,6 +33,7 @@
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/parallel.h"
+#include "access/relation.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/table.h"
@@ -464,9 +465,36 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
{
bytea *options;
amoptions_function amoptsfn;
+ CommonRdOptions *common = &relation->rd_common_options;
+ const TableAmRoutine *tableam = NULL;
relation->rd_options = NULL;
+ /*
+ * Fill the rd_common_options with default values. That might be later
+ * changed by extractRelOptions().
+ */
+ common->autovacuum.enabled = true;
+ common->autovacuum.vacuum_threshold = -1;
+ common->autovacuum.vacuum_ins_threshold = -2;
+ common->autovacuum.analyze_threshold = -1;
+ common->autovacuum.vacuum_cost_limit = -1;
+ common->autovacuum.freeze_min_age = -1;
+ common->autovacuum.freeze_max_age = -1;
+ common->autovacuum.freeze_table_age = -1;
+ common->autovacuum.multixact_freeze_min_age = -1;
+ common->autovacuum.multixact_freeze_max_age = -1;
+ common->autovacuum.multixact_freeze_table_age = -1;
+ common->autovacuum.log_min_duration = -1;
+ common->autovacuum.vacuum_cost_delay = -1;
+ common->autovacuum.vacuum_scale_factor = -1;
+ common->autovacuum.vacuum_ins_scale_factor = -1;
+ common->autovacuum.analyze_scale_factor = -1;
+ common->parallel_workers = -1;
+ common->user_catalog_table = false;
+ common->vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO;
+ common->vacuum_truncate = true;
+
/*
* Look up any AM-specific parse function; fall out if relkind should not
* have options.
@@ -478,6 +506,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
case RELKIND_VIEW:
case RELKIND_MATVIEW:
case RELKIND_PARTITIONED_TABLE:
+ tableam = relation->rd_tableam;
amoptsfn = NULL;
break;
case RELKIND_INDEX:
@@ -493,7 +522,9 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
* we might not have any other for pg_class yet (consider executing this
* code for pg_class itself)
*/
- options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
+ options = extractRelOptions(tuple, GetPgClassDescriptor(),
+ tableam, amoptsfn,
+ &relation->rd_common_options);
/*
* Copy parsed data into CacheMemoryContext. To guard against the
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 81829b8270..342b9cdd6e 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -21,6 +21,7 @@
#include "access/amapi.h"
#include "access/htup.h"
+#include "access/tableam.h"
#include "access/tupdesc.h"
#include "nodes/pg_list.h"
#include "storage/lock.h"
@@ -224,7 +225,9 @@ extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool acceptOidsOff, bool isReset);
extern List *untransformRelOptions(Datum options);
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
- amoptions_function amoptions);
+ const TableAmRoutine *tableam,
+ amoptions_function amoptions,
+ CommonRdOptions *common);
extern void *build_reloptions(Datum reloptions, bool validate,
relopt_kind kind,
Size relopt_struct_size,
@@ -233,9 +236,8 @@ extern void *build_reloptions(Datum reloptions, bool validate,
extern void *build_local_reloptions(local_relopts *relopts, Datum options,
bool validate);
-extern bytea *default_reloptions(Datum reloptions, bool validate,
- relopt_kind kind);
-extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
+extern bytea *heap_reloptions(char relkind, Datum reloptions,
+ CommonRdOptions *common, bool validate);
extern bytea *view_reloptions(Datum reloptions, bool validate);
extern bytea *partitioned_table_reloptions(Datum reloptions, bool validate);
extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index be198fa315..c38e83fe74 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -746,6 +746,34 @@ typedef struct TableAmRoutine
int32 slicelength,
struct varlena *result);
+ /*
+ * This callback parses and validates the reloptions array for a table.
+ *
+ * This is called only when a non-null reloptions array exists for the
+ * table. 'reloptions' is a text array containing entries of the form
+ * "name=value". The function should construct a bytea value, which will
+ * be copied into the rd_options field of the table's relcache entry. The
+ * data contents of the bytea value are open for the access method to
+ * define.
+ *
+ * The '*common' represents the common values, which the table access
+ * method exposes for autovacuum, query planner, and others. The caller
+ * should fill them with default values. The table access method may
+ * modify them on the base of options specified by a user.
+ *
+ * When 'validate' is true, the function should report a suitable error
+ * message if any of the options are unrecognized or have invalid values;
+ * when 'validate' is false, invalid entries should be silently ignored.
+ * ('validate' is false when loading options already stored in pg_catalog;
+ * an invalid entry could only be found if the access method has changed
+ * its rules for options, and in that case ignoring obsolete entries is
+ * appropriate.)
+ *
+ * It is OK to return NULL if default behavior is wanted.
+ */
+ bytea *(*reloptions) (char relkind, Datum reloptions,
+ CommonRdOptions *common, bool validate);
+
/* ------------------------------------------------------------------------
* Planner related functions.
@@ -1908,7 +1936,7 @@ table_relation_needs_toast_table(Relation rel)
static inline Oid
table_relation_toast_am(Relation rel)
{
- return rel->rd_tableam->relation_toast_am(rel);
+ return rel->rd_tableam ? rel->rd_tableam->relation_toast_am(rel) : InvalidOid;
}
/*
@@ -1945,6 +1973,27 @@ table_relation_fetch_toast_slice(Relation toastrel, Oid valueid,
result);
}
+/*
+ * Parse table options without knowledge of particular table.
+ */
+static inline bytea *
+tableam_reloptions(const TableAmRoutine *tableam, char relkind,
+ Datum reloptions, CommonRdOptions *common, bool validate)
+{
+ return tableam->reloptions(relkind, reloptions, common, validate);
+}
+
+/*
+ * Parse options for given table.
+ */
+static inline bytea *
+table_reloptions(Relation rel, char relkind,
+ Datum reloptions, CommonRdOptions *common, bool validate)
+{
+ return tableam_reloptions(rel->rd_tableam, relkind, reloptions,
+ common, validate);
+}
+
/* ----------------------------------------------------------------------------
* Planner related functionality
@@ -2123,6 +2172,7 @@ extern void table_block_relation_estimate_size(Relation rel,
*/
extern const TableAmRoutine *GetTableAmRoutine(Oid amhandler);
+extern const TableAmRoutine *GetTableAmRoutineByAmOid(Oid amoid);
/* ----------------------------------------------------------------------------
* Functions in heapam_handler.c
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index f25f769af2..4e6c4074bc 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -48,6 +48,52 @@ typedef struct LockInfoData
typedef LockInfoData *LockInfo;
+ /* autovacuum-related reloptions. */
+typedef struct AutoVacOpts
+{
+ bool enabled;
+ int vacuum_threshold;
+ int vacuum_ins_threshold;
+ int analyze_threshold;
+ int vacuum_cost_limit;
+ int freeze_min_age;
+ int freeze_max_age;
+ int freeze_table_age;
+ int multixact_freeze_min_age;
+ int multixact_freeze_max_age;
+ int multixact_freeze_table_age;
+ int log_min_duration;
+ float8 vacuum_cost_delay;
+ float8 vacuum_scale_factor;
+ float8 vacuum_ins_scale_factor;
+ float8 analyze_scale_factor;
+} AutoVacOpts;
+
+/* StdRdOptions->vacuum_index_cleanup values */
+typedef enum StdRdOptIndexCleanup
+{
+ STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0,
+ STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF,
+ STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON,
+} StdRdOptIndexCleanup;
+
+/*
+ * CommonRdOptions
+ * Contents of rd_common_options for tables. It contains the options,
+ * which the table access method exposes for autovacuum, query planner,
+ * and others. These options could be by decision of table AM directly
+ * specified by a user or calculated in some way.
+ */
+typedef struct CommonRdOptions
+{
+ AutoVacOpts autovacuum; /* autovacuum-related options */
+ bool user_catalog_table; /* use as an additional catalog relation */
+ int parallel_workers; /* max number of parallel workers */
+ StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */
+ bool vacuum_truncate; /* enables vacuum to truncate a relation */
+} CommonRdOptions;
+
+
/*
* Here are the contents of a relation cache entry.
*/
@@ -168,11 +214,19 @@ typedef struct RelationData
PublicationDesc *rd_pubdesc; /* publication descriptor, or NULL */
/*
- * rd_options is set whenever rd_rel is loaded into the relcache entry.
- * Note that you can NOT look into rd_rel for this data. NULL means "use
- * defaults".
+ * rd_options and rd_common_options are set whenever rd_rel is loaded into
+ * the relcache entry. Note that you can NOT look into rd_rel for this
+ * data.
+ */
+ CommonRdOptions rd_common_options; /* the options, which table AM exposes
+ * for external usage */
+
+ /*
+ * am-specific part of pg_class.reloptions parsed by table am specific
+ * structure (e.g. struct HeapRdOptions) Contents are not to be accessed
+ * outside of table am. NULL means "use defaults".
*/
- bytea *rd_options; /* parsed pg_class.reloptions */
+ bytea *rd_options;
/*
* Oid of the handler for this relation. For an index this is a function
@@ -297,88 +351,42 @@ typedef struct ForeignKeyCacheInfo
Oid conpfeqop[INDEX_MAX_KEYS] pg_node_attr(array_size(nkeys));
} ForeignKeyCacheInfo;
-
/*
- * StdRdOptions
- * Standard contents of rd_options for heaps.
- *
- * RelationGetFillFactor() and RelationGetTargetPageFreeSpace() can only
- * be applied to relations that use this format or a superset for
- * private options data.
+ * HeapRdOptions
+ * Contents of rd_options specific for heap tables.
*/
- /* autovacuum-related reloptions. */
-typedef struct AutoVacOpts
-{
- bool enabled;
- int vacuum_threshold;
- int vacuum_ins_threshold;
- int analyze_threshold;
- int vacuum_cost_limit;
- int freeze_min_age;
- int freeze_max_age;
- int freeze_table_age;
- int multixact_freeze_min_age;
- int multixact_freeze_max_age;
- int multixact_freeze_table_age;
- int log_min_duration;
- float8 vacuum_cost_delay;
- float8 vacuum_scale_factor;
- float8 vacuum_ins_scale_factor;
- float8 analyze_scale_factor;
-} AutoVacOpts;
-
-/* StdRdOptions->vacuum_index_cleanup values */
-typedef enum StdRdOptIndexCleanup
-{
- STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0,
- STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF,
- STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON,
-} StdRdOptIndexCleanup;
-
-typedef struct StdRdOptions
+typedef struct HeapRdOptions
{
int32 vl_len_; /* varlena header (do not touch directly!) */
+ CommonRdOptions common;
int fillfactor; /* page fill factor in percent (0..100) */
int toast_tuple_target; /* target for tuple toasting */
- AutoVacOpts autovacuum; /* autovacuum-related options */
- bool user_catalog_table; /* use as an additional catalog relation */
- int parallel_workers; /* max number of parallel workers */
- StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */
- bool vacuum_truncate; /* enables vacuum to truncate a relation */
-} StdRdOptions;
+} HeapRdOptions;
#define HEAP_MIN_FILLFACTOR 10
#define HEAP_DEFAULT_FILLFACTOR 100
/*
- * RelationGetToastTupleTarget
- * Returns the relation's toast_tuple_target. Note multiple eval of argument!
+ * HeapGetFillFactor
+ * Returns the heap relation's fillfactor. Note multiple eval of argument!
*/
-#define RelationGetToastTupleTarget(relation, defaulttarg) \
+#define HeapGetFillFactor(relation, defaultff) \
((relation)->rd_options ? \
- ((StdRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
+ ((HeapRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
/*
- * RelationGetFillFactor
- * Returns the relation's fillfactor. Note multiple eval of argument!
- */
-#define RelationGetFillFactor(relation, defaultff) \
- ((relation)->rd_options ? \
- ((StdRdOptions *) (relation)->rd_options)->fillfactor : (defaultff))
-
-/*
- * RelationGetTargetPageUsage
+ * HeapGetTargetPageUsage
* Returns the relation's desired space usage per page in bytes.
*/
-#define RelationGetTargetPageUsage(relation, defaultff) \
- (BLCKSZ * RelationGetFillFactor(relation, defaultff) / 100)
+#define HeapGetTargetPageUsage(relation, defaultff) \
+ (BLCKSZ * HeapGetFillFactor(relation, defaultff) / 100)
/*
- * RelationGetTargetPageFreeSpace
+ * HeapGetTargetPageFreeSpace
* Returns the relation's desired freespace per page in bytes.
*/
-#define RelationGetTargetPageFreeSpace(relation, defaultff) \
- (BLCKSZ * (100 - RelationGetFillFactor(relation, defaultff)) / 100)
+#define HeapGetTargetPageFreeSpace(relation, defaultff) \
+ (BLCKSZ * (100 - HeapGetFillFactor(relation, defaultff)) / 100)
/*
* RelationIsUsedAsCatalogTable
@@ -386,19 +394,17 @@ typedef struct StdRdOptions
* from the pov of logical decoding. Note multiple eval of argument!
*/
#define RelationIsUsedAsCatalogTable(relation) \
- ((relation)->rd_options && \
- ((relation)->rd_rel->relkind == RELKIND_RELATION || \
+ (((relation)->rd_rel->relkind == RELKIND_RELATION || \
(relation)->rd_rel->relkind == RELKIND_MATVIEW) ? \
- ((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false)
+ (relation)->rd_common_options.user_catalog_table : false)
/*
* RelationGetParallelWorkers
* Returns the relation'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) \
+ ((relation)->rd_common_options.parallel_workers)
/* ViewOptions->check_option values */
typedef enum ViewOptCheckOption
diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 256799f520..8f66152539 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -36,6 +36,7 @@ SUBDIRS = \
test_rls_hooks \
test_shm_mq \
test_slru \
+ test_tam_options \
test_tidstore \
unsafe_tests \
worker_spi \
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index d8fe059d23..235e342dfa 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -35,6 +35,7 @@ subdir('test_resowner')
subdir('test_rls_hooks')
subdir('test_shm_mq')
subdir('test_slru')
+subdir('test_tam_options')
subdir('test_tidstore')
subdir('unsafe_tests')
subdir('worker_spi')
diff --git a/src/test/modules/test_tam_options/.gitignore b/src/test/modules/test_tam_options/.gitignore
new file mode 100644
index 0000000000..5dcb3ff972
--- /dev/null
+++ b/src/test/modules/test_tam_options/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/src/test/modules/test_tam_options/Makefile b/src/test/modules/test_tam_options/Makefile
new file mode 100644
index 0000000000..bd6d4599a1
--- /dev/null
+++ b/src/test/modules/test_tam_options/Makefile
@@ -0,0 +1,23 @@
+# src/test/modules/test_tam_options/Makefile
+
+MODULE_big = test_tam_options
+OBJS = \
+ $(WIN32RES) \
+ test_tam_options.o
+PGFILEDESC = "test_tam_options - test code for table access method reloptions"
+
+EXTENSION = test_tam_options
+DATA = test_tam_options--1.0.sql
+
+REGRESS = test_tam_options
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_tam_options
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_tam_options/expected/test_tam_options.out b/src/test/modules/test_tam_options/expected/test_tam_options.out
new file mode 100644
index 0000000000..c921afcb27
--- /dev/null
+++ b/src/test/modules/test_tam_options/expected/test_tam_options.out
@@ -0,0 +1,36 @@
+CREATE EXTENSION test_tam_options;
+-- encourage use of parallel plans
+SET parallel_setup_cost = 0;
+SET parallel_tuple_cost = 0;
+SET min_parallel_table_scan_size = 0;
+SET max_parallel_workers_per_gather = 4;
+CREATE TABLE test (i int) USING heap_alter_options;
+INSERT INTO test SELECT i FROM generate_series(1, 10000) i;
+VACUUM ANALYZE test;
+EXPLAIN (costs off)
+SELECT * FROM test;
+ QUERY PLAN
+---------------------------------
+ Gather
+ Workers Planned: 4
+ -> Parallel Seq Scan on test
+(3 rows)
+
+ALTER TABLE test SET (enable_parallel = OFF);
+EXPLAIN (costs off)
+SELECT * FROM test;
+ QUERY PLAN
+------------------
+ Seq Scan on test
+(1 row)
+
+ALTER TABLE test SET (enable_parallel = ON);
+EXPLAIN (costs off)
+SELECT * FROM test;
+ QUERY PLAN
+---------------------------------
+ Gather
+ Workers Planned: 4
+ -> Parallel Seq Scan on test
+(3 rows)
+
diff --git a/src/test/modules/test_tam_options/meson.build b/src/test/modules/test_tam_options/meson.build
new file mode 100644
index 0000000000..d41a32a680
--- /dev/null
+++ b/src/test/modules/test_tam_options/meson.build
@@ -0,0 +1,33 @@
+# Copyright (c) 2024, PostgreSQL Global Development Group
+
+test_tam_options_sources = files(
+ 'test_tam_options.c',
+)
+
+if host_system == 'windows'
+ test_tam_options_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'test_tam_options',
+ '--FILEDESC', 'test_tam_options - test code for table access method reloptions',])
+endif
+
+test_tam_options = shared_module('test_tam_options',
+ test_tam_options_sources,
+ kwargs: pg_test_mod_args,
+)
+test_install_libs += test_tam_options
+
+test_install_data += files(
+ 'test_tam_options.control',
+ 'test_tam_options--1.0.sql',
+)
+
+tests += {
+ 'name': 'test_tam_options',
+ 'sd': meson.current_source_dir(),
+ 'bd': meson.current_build_dir(),
+ 'regress': {
+ 'sql': [
+ 'test_tam_options',
+ ],
+ },
+}
diff --git a/src/test/modules/test_tam_options/sql/test_tam_options.sql b/src/test/modules/test_tam_options/sql/test_tam_options.sql
new file mode 100644
index 0000000000..4f97504656
--- /dev/null
+++ b/src/test/modules/test_tam_options/sql/test_tam_options.sql
@@ -0,0 +1,25 @@
+CREATE EXTENSION test_tam_options;
+
+-- encourage use of parallel plans
+SET parallel_setup_cost = 0;
+SET parallel_tuple_cost = 0;
+SET min_parallel_table_scan_size = 0;
+SET max_parallel_workers_per_gather = 4;
+
+CREATE TABLE test (i int) USING heap_alter_options;
+
+INSERT INTO test SELECT i FROM generate_series(1, 10000) i;
+VACUUM ANALYZE test;
+
+EXPLAIN (costs off)
+SELECT * FROM test;
+
+ALTER TABLE test SET (enable_parallel = OFF);
+
+EXPLAIN (costs off)
+SELECT * FROM test;
+
+ALTER TABLE test SET (enable_parallel = ON);
+
+EXPLAIN (costs off)
+SELECT * FROM test;
diff --git a/src/test/modules/test_tam_options/test_tam_options--1.0.sql b/src/test/modules/test_tam_options/test_tam_options--1.0.sql
new file mode 100644
index 0000000000..07569f7b5f
--- /dev/null
+++ b/src/test/modules/test_tam_options/test_tam_options--1.0.sql
@@ -0,0 +1,12 @@
+/* src/test/modules/test_tam_options/test_tam_options--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_tam_options" to load this file. \quit
+
+CREATE FUNCTION heap_alter_options_tam_handler(internal)
+RETURNS table_am_handler
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT;
+
+CREATE ACCESS METHOD heap_alter_options TYPE TABLE
+HANDLER heap_alter_options_tam_handler;
diff --git a/src/test/modules/test_tam_options/test_tam_options.c b/src/test/modules/test_tam_options/test_tam_options.c
new file mode 100644
index 0000000000..2700861637
--- /dev/null
+++ b/src/test/modules/test_tam_options/test_tam_options.c
@@ -0,0 +1,66 @@
+/*--------------------------------------------------------------------------
+ *
+ * test_tam_options.c
+ * Test code for table access method reloptions.
+ *
+ * Copyright (c) 2024, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/test/modules/test_tam_options/test_tam_options.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "access/tableam.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(heap_alter_options_tam_handler);
+
+/* An alternative relation options for heap */
+typedef struct
+{
+ int32 vl_len_; /* varlena header (do not touch directly!) */
+ bool enable_parallel; /* enable parallel scans? */
+} HeapAlterRdOptions;
+
+static bytea *
+heap_alter_reloptions(char relkind, Datum reloptions,
+ CommonRdOptions *common, bool validate)
+{
+ local_relopts relopts;
+ HeapAlterRdOptions *result;
+
+ Assert(relkind == RELKIND_RELATION ||
+ relkind == RELKIND_TOASTVALUE ||
+ relkind == RELKIND_MATVIEW);
+
+ init_local_reloptions(&relopts, sizeof(HeapAlterRdOptions));
+ add_local_bool_reloption(&relopts, "enable_parallel",
+ "enable parallel scan", true,
+ offsetof(HeapAlterRdOptions, enable_parallel));
+
+ result = (HeapAlterRdOptions *) build_local_reloptions(&relopts,
+ reloptions,
+ validate);
+
+ if (result != NULL && common != NULL)
+ {
+ common->parallel_workers = result->enable_parallel ? -1 : 0;
+ }
+
+ return (bytea *) result;
+}
+
+Datum
+heap_alter_options_tam_handler(PG_FUNCTION_ARGS)
+{
+ static TableAmRoutine tam_routine;
+
+ tam_routine = *GetHeapamTableAmRoutine();
+ tam_routine.reloptions = heap_alter_reloptions;
+
+ PG_RETURN_POINTER(&tam_routine);
+}
diff --git a/src/test/modules/test_tam_options/test_tam_options.control b/src/test/modules/test_tam_options/test_tam_options.control
new file mode 100644
index 0000000000..dd6682edcd
--- /dev/null
+++ b/src/test/modules/test_tam_options/test_tam_options.control
@@ -0,0 +1,4 @@
+comment = 'Test code for table access method reloptions'
+default_version = '1.0'
+module_pathname = '$libdir/test_tam_options'
+relocatable = true
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 6e0717c8c4..80f8261b7f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -442,6 +442,7 @@ CommentStmt
CommitTimestampEntry
CommitTimestampShared
CommonEntry
+CommonRdOptions
CommonTableExpr
CompareScalarsContext
CompiledExprState
@@ -1131,6 +1132,7 @@ HeadlineParsedText
HeadlineWordEntry
HeapCheckContext
HeapPageFreeze
+HeapRdOptions
HeapScanDesc
HeapTuple
HeapTupleData
@@ -2719,7 +2721,6 @@ StatsElem
StatsExtInfo
StdAnalyzeData
StdRdOptIndexCleanup
-StdRdOptions
Step
StopList
StrategyNumber
--
2.39.2 (Apple Git-143)