Skip to content

Commit 9bd99f4

Browse files
committed
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
1 parent 6f3d8d5 commit 9bd99f4

29 files changed

+639
-161
lines changed

src/backend/access/common/reloptions.c

Lines changed: 86 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "access/nbtree.h"
2525
#include "access/reloptions.h"
2626
#include "access/spgist_private.h"
27+
#include "access/tableam.h"
2728
#include "catalog/pg_type.h"
2829
#include "commands/defrem.h"
2930
#include "commands/tablespace.h"
@@ -44,7 +45,7 @@
4445
* value, upper and lower bounds (if applicable); for strings, consider a
4546
* validation routine.
4647
* (ii) add a record below (or use add_<type>_reloption).
47-
* (iii) add it to the appropriate options struct (perhaps StdRdOptions)
48+
* (iii) add it to the appropriate options struct (perhaps HeapRdOptions)
4849
* (iv) add it to the appropriate handling routine (perhaps
4950
* default_reloptions)
5051
* (v) make sure the lock level is set correctly for that operation
@@ -1374,10 +1375,16 @@ untransformRelOptions(Datum options)
13741375
* tupdesc is pg_class' tuple descriptor. amoptions is a pointer to the index
13751376
* AM's options parser function in the case of a tuple corresponding to an
13761377
* index, or NULL otherwise.
1378+
*
1379+
* If common pointer is provided, then the corresponding struct will be
1380+
* filled with options that table AM exposes for external usage. That must
1381+
* be filled with defaults before passing here.
13771382
*/
1383+
13781384
bytea *
13791385
extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
1380-
amoptions_function amoptions)
1386+
const TableAmRoutine *tableam, amoptions_function amoptions,
1387+
CommonRdOptions *common)
13811388
{
13821389
bytea *options;
13831390
bool isnull;
@@ -1399,7 +1406,8 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
13991406
case RELKIND_RELATION:
14001407
case RELKIND_TOASTVALUE:
14011408
case RELKIND_MATVIEW:
1402-
options = heap_reloptions(classForm->relkind, datum, false);
1409+
options = tableam_reloptions(tableam, classForm->relkind,
1410+
datum, common, false);
14031411
break;
14041412
case RELKIND_PARTITIONED_TABLE:
14051413
options = partitioned_table_reloptions(datum, false);
@@ -1695,7 +1703,7 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len,
16951703
* Given the result from parseRelOptions, allocate a struct that's of the
16961704
* specified base size plus any extra space that's needed for string variables.
16971705
*
1698-
* "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or
1706+
* "base" should be sizeof(struct) of the reloptions struct (HeapRdOptions or
16991707
* equivalent).
17001708
*/
17011709
static void *
@@ -1832,59 +1840,95 @@ fillRelOptions(void *rdopts, Size basesize,
18321840

18331841

18341842
/*
1835-
* Option parser for anything that uses StdRdOptions.
1843+
* Option parser for anything that uses HeapRdOptions.
18361844
*/
1837-
bytea *
1845+
static bytea *
18381846
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
18391847
{
18401848
static const relopt_parse_elt tab[] = {
1841-
{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
1849+
{"fillfactor", RELOPT_TYPE_INT, offsetof(HeapRdOptions, fillfactor)},
18421850
{"autovacuum_enabled", RELOPT_TYPE_BOOL,
1843-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
1851+
offsetof(HeapRdOptions, common) +
1852+
offsetof(CommonRdOptions, autovacuum) +
1853+
offsetof(AutoVacOpts, enabled)},
18441854
{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
1845-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
1855+
offsetof(HeapRdOptions, common) +
1856+
offsetof(CommonRdOptions, autovacuum) +
1857+
offsetof(AutoVacOpts, vacuum_threshold)},
18461858
{"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT,
1847-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)},
1859+
offsetof(HeapRdOptions, common) +
1860+
offsetof(CommonRdOptions, autovacuum) +
1861+
offsetof(AutoVacOpts, vacuum_ins_threshold)},
18481862
{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
1849-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
1863+
offsetof(HeapRdOptions, common) +
1864+
offsetof(CommonRdOptions, autovacuum) +
1865+
offsetof(AutoVacOpts, analyze_threshold)},
18501866
{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
1851-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
1867+
offsetof(HeapRdOptions, common) +
1868+
offsetof(CommonRdOptions, autovacuum) +
1869+
offsetof(AutoVacOpts, vacuum_cost_limit)},
18521870
{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
1853-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
1871+
offsetof(HeapRdOptions, common) +
1872+
offsetof(CommonRdOptions, autovacuum) +
1873+
offsetof(AutoVacOpts, freeze_min_age)},
18541874
{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
1855-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
1875+
offsetof(HeapRdOptions, common) +
1876+
offsetof(CommonRdOptions, autovacuum) +
1877+
offsetof(AutoVacOpts, freeze_max_age)},
18561878
{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
1857-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
1879+
offsetof(HeapRdOptions, common) +
1880+
offsetof(CommonRdOptions, autovacuum) +
1881+
offsetof(AutoVacOpts, freeze_table_age)},
18581882
{"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT,
1859-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)},
1883+
offsetof(HeapRdOptions, common) +
1884+
offsetof(CommonRdOptions, autovacuum) +
1885+
offsetof(AutoVacOpts, multixact_freeze_min_age)},
18601886
{"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT,
1861-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)},
1887+
offsetof(HeapRdOptions, common) +
1888+
offsetof(CommonRdOptions, autovacuum) +
1889+
offsetof(AutoVacOpts, multixact_freeze_max_age)},
18621890
{"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT,
1863-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)},
1891+
offsetof(HeapRdOptions, common) +
1892+
offsetof(CommonRdOptions, autovacuum) +
1893+
offsetof(AutoVacOpts, multixact_freeze_table_age)},
18641894
{"log_autovacuum_min_duration", RELOPT_TYPE_INT,
1865-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_min_duration)},
1895+
offsetof(HeapRdOptions, common) +
1896+
offsetof(CommonRdOptions, autovacuum) +
1897+
offsetof(AutoVacOpts, log_min_duration)},
18661898
{"toast_tuple_target", RELOPT_TYPE_INT,
1867-
offsetof(StdRdOptions, toast_tuple_target)},
1899+
offsetof(HeapRdOptions, toast_tuple_target)},
18681900
{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL,
1869-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
1901+
offsetof(HeapRdOptions, common) +
1902+
offsetof(CommonRdOptions, autovacuum) +
1903+
offsetof(AutoVacOpts, vacuum_cost_delay)},
18701904
{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
1871-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
1905+
offsetof(HeapRdOptions, common) +
1906+
offsetof(CommonRdOptions, autovacuum) +
1907+
offsetof(AutoVacOpts, vacuum_scale_factor)},
18721908
{"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL,
1873-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
1909+
offsetof(HeapRdOptions, common) +
1910+
offsetof(CommonRdOptions, autovacuum) +
1911+
offsetof(AutoVacOpts, vacuum_ins_scale_factor)},
18741912
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
1875-
offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)},
1913+
offsetof(HeapRdOptions, common) +
1914+
offsetof(CommonRdOptions, autovacuum) +
1915+
offsetof(AutoVacOpts, analyze_scale_factor)},
18761916
{"user_catalog_table", RELOPT_TYPE_BOOL,
1877-
offsetof(StdRdOptions, user_catalog_table)},
1917+
offsetof(HeapRdOptions, common) +
1918+
offsetof(CommonRdOptions, user_catalog_table)},
18781919
{"parallel_workers", RELOPT_TYPE_INT,
1879-
offsetof(StdRdOptions, parallel_workers)},
1920+
offsetof(HeapRdOptions, common) +
1921+
offsetof(CommonRdOptions, parallel_workers)},
18801922
{"vacuum_index_cleanup", RELOPT_TYPE_ENUM,
1881-
offsetof(StdRdOptions, vacuum_index_cleanup)},
1923+
offsetof(HeapRdOptions, common) +
1924+
offsetof(CommonRdOptions, vacuum_index_cleanup)},
18821925
{"vacuum_truncate", RELOPT_TYPE_BOOL,
1883-
offsetof(StdRdOptions, vacuum_truncate)}
1926+
offsetof(HeapRdOptions, common) +
1927+
offsetof(CommonRdOptions, vacuum_truncate)}
18841928
};
18851929

18861930
return (bytea *) build_reloptions(reloptions, validate, kind,
1887-
sizeof(StdRdOptions),
1931+
sizeof(HeapRdOptions),
18881932
tab, lengthof(tab));
18891933
}
18901934

@@ -2016,26 +2060,33 @@ view_reloptions(Datum reloptions, bool validate)
20162060
* Parse options for heaps, views and toast tables.
20172061
*/
20182062
bytea *
2019-
heap_reloptions(char relkind, Datum reloptions, bool validate)
2063+
heap_reloptions(char relkind, Datum reloptions,
2064+
CommonRdOptions *common, bool validate)
20202065
{
2021-
StdRdOptions *rdopts;
2066+
HeapRdOptions *rdopts;
20222067

20232068
switch (relkind)
20242069
{
20252070
case RELKIND_TOASTVALUE:
2026-
rdopts = (StdRdOptions *)
2071+
rdopts = (HeapRdOptions *)
20272072
default_reloptions(reloptions, validate, RELOPT_KIND_TOAST);
20282073
if (rdopts != NULL)
20292074
{
20302075
/* adjust default-only parameters for TOAST relations */
20312076
rdopts->fillfactor = 100;
2032-
rdopts->autovacuum.analyze_threshold = -1;
2033-
rdopts->autovacuum.analyze_scale_factor = -1;
2077+
rdopts->common.autovacuum.analyze_threshold = -1;
2078+
rdopts->common.autovacuum.analyze_scale_factor = -1;
20342079
}
2080+
if (rdopts != NULL && common != NULL)
2081+
*common = rdopts->common;
20352082
return (bytea *) rdopts;
20362083
case RELKIND_RELATION:
20372084
case RELKIND_MATVIEW:
2038-
return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
2085+
rdopts = (HeapRdOptions *)
2086+
default_reloptions(reloptions, validate, RELOPT_KIND_HEAP);
2087+
if (rdopts != NULL && common != NULL)
2088+
*common = rdopts->common;
2089+
return (bytea *) rdopts;
20392090
default:
20402091
/* other relkinds are not supported */
20412092
return NULL;

src/backend/access/heap/heapam.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,8 +2279,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
22792279
Assert(!(options & HEAP_INSERT_NO_LOGICAL));
22802280

22812281
needwal = RelationNeedsWAL(relation);
2282-
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
2283-
HEAP_DEFAULT_FILLFACTOR);
2282+
saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
2283+
HEAP_DEFAULT_FILLFACTOR);
22842284

22852285
/* Toast and set header data in all the slots */
22862286
heaptuples = palloc(ntuples * sizeof(HeapTuple));

src/backend/access/heap/heapam_handler.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "access/heapam.h"
2424
#include "access/heaptoast.h"
2525
#include "access/multixact.h"
26+
#include "access/reloptions.h"
2627
#include "access/rewriteheap.h"
2728
#include "access/syncscan.h"
2829
#include "access/tableam.h"
@@ -2161,6 +2162,17 @@ heapam_relation_toast_am(Relation rel)
21612162
return rel->rd_rel->relam;
21622163
}
21632164

2165+
static bytea *
2166+
heapam_reloptions(char relkind, Datum reloptions,
2167+
CommonRdOptions *common, bool validate)
2168+
{
2169+
Assert(relkind == RELKIND_RELATION ||
2170+
relkind == RELKIND_TOASTVALUE ||
2171+
relkind == RELKIND_MATVIEW);
2172+
2173+
return heap_reloptions(relkind, reloptions, common, validate);
2174+
}
2175+
21642176

21652177
/* ------------------------------------------------------------------------
21662178
* Planner related callbacks for the heap AM
@@ -2710,6 +2722,7 @@ static const TableAmRoutine heapam_methods = {
27102722
.relation_needs_toast_table = heapam_relation_needs_toast_table,
27112723
.relation_toast_am = heapam_relation_toast_am,
27122724
.relation_fetch_toast_slice = heap_fetch_toast_slice,
2725+
.reloptions = heapam_reloptions,
27132726

27142727
.relation_estimate_size = heapam_estimate_rel_size,
27152728

src/backend/access/heap/heaptoast.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
#include "access/toast_internals.h"
3333
#include "utils/fmgroids.h"
3434

35+
/*
36+
* HeapGetToastTupleTarget
37+
* Returns the heap relation's toast_tuple_target. Note multiple eval of argument!
38+
*/
39+
#define HeapGetToastTupleTarget(relation, defaulttarg) \
40+
((HeapRdOptions *) (relation)->rd_options ? \
41+
((HeapRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg))
3542

3643
/* ----------
3744
* heap_toast_delete -
@@ -174,7 +181,7 @@ heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
174181
hoff += BITMAPLEN(numAttrs);
175182
hoff = MAXALIGN(hoff);
176183
/* now convert to a limit on the tuple data size */
177-
maxDataLen = RelationGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
184+
maxDataLen = HeapGetToastTupleTarget(rel, TOAST_TUPLE_TARGET) - hoff;
178185

179186
/*
180187
* Look for attributes with attstorage EXTENDED to compress. Also find

src/backend/access/heap/hio.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
536536
len, MaxHeapTupleSize)));
537537

538538
/* Compute desired extra freespace due to fillfactor option */
539-
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
540-
HEAP_DEFAULT_FILLFACTOR);
539+
saveFreeSpace = HeapGetTargetPageFreeSpace(relation,
540+
HEAP_DEFAULT_FILLFACTOR);
541541

542542
/*
543543
* Since pages without tuples can still have line pointers, we consider

src/backend/access/heap/pruneheap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
235235
* important than sometimes getting a wrong answer in what is after all
236236
* just a heuristic estimate.
237237
*/
238-
minfree = RelationGetTargetPageFreeSpace(relation,
239-
HEAP_DEFAULT_FILLFACTOR);
238+
minfree = HeapGetTargetPageFreeSpace(relation,
239+
HEAP_DEFAULT_FILLFACTOR);
240240
minfree = Max(minfree, BLCKSZ / 10);
241241

242242
if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)

src/backend/access/heap/rewriteheap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,8 +641,8 @@ raw_heap_insert(RewriteState state, HeapTuple tup)
641641
len, MaxHeapTupleSize)));
642642

643643
/* Compute desired extra freespace due to fillfactor option */
644-
saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel,
645-
HEAP_DEFAULT_FILLFACTOR);
644+
saveFreeSpace = HeapGetTargetPageFreeSpace(state->rs_new_rel,
645+
HEAP_DEFAULT_FILLFACTOR);
646646

647647
/* Now we can check to see if there's enough free space already. */
648648
page = (Page) state->rs_buffer;

src/backend/access/table/tableam.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,7 @@ table_block_relation_estimate_size(Relation rel, int32 *attr_widths,
750750
* The other branch considers it implicitly by calculating density
751751
* from actual relpages/reltuples statistics.
752752
*/
753-
fillfactor = RelationGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
753+
fillfactor = HeapGetFillFactor(rel, HEAP_DEFAULT_FILLFACTOR);
754754

755755
tuple_width = get_rel_data_width(rel, attr_widths);
756756
tuple_width += overhead_bytes_per_tuple;

src/backend/access/table/tableamapi.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313

1414
#include "access/tableam.h"
1515
#include "access/xact.h"
16+
#include "catalog/pg_am.h"
1617
#include "commands/defrem.h"
1718
#include "miscadmin.h"
1819
#include "utils/guc_hooks.h"
20+
#include "utils/syscache.h"
1921

2022

2123
/*
@@ -98,6 +100,29 @@ GetTableAmRoutine(Oid amhandler)
98100
return routine;
99101
}
100102

103+
/*
104+
* GetTableAmRoutineByAmOid
105+
* Given the table access method oid get its TableAmRoutine struct, which
106+
* will be palloc'd in the caller's memory context.
107+
*/
108+
const TableAmRoutine *
109+
GetTableAmRoutineByAmOid(Oid amoid)
110+
{
111+
HeapTuple ht_am;
112+
Form_pg_am amrec;
113+
const TableAmRoutine *tableam = NULL;
114+
115+
ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
116+
if (!HeapTupleIsValid(ht_am))
117+
elog(ERROR, "cache lookup failed for access method %u",
118+
amoid);
119+
amrec = (Form_pg_am) GETSTRUCT(ht_am);
120+
121+
tableam = GetTableAmRoutine(amrec->amhandler);
122+
ReleaseSysCache(ht_am);
123+
return tableam;
124+
}
125+
101126
/* check_hook: validate new default_table_access_method */
102127
bool
103128
check_default_table_access_method(char **newval, void **extra, GucSource source)

src/backend/commands/createas.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ create_ctas_internal(List *attrList, IntoClause *into)
8585
Datum toast_options;
8686
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
8787
ObjectAddress intoRelationAddr;
88+
const TableAmRoutine *tableam = NULL;
89+
Oid accessMethodId = InvalidOid;
90+
Relation rel;
8891

8992
/* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
9093
is_matview = (into->viewQuery != NULL);
@@ -125,7 +128,15 @@ create_ctas_internal(List *attrList, IntoClause *into)
125128
validnsps,
126129
true, false);
127130

128-
(void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
131+
rel = relation_open(intoRelationAddr.objectId, AccessShareLock);
132+
accessMethodId = table_relation_toast_am(rel);
133+
relation_close(rel, AccessShareLock);
134+
135+
if (OidIsValid(accessMethodId))
136+
{
137+
tableam = GetTableAmRoutineByAmOid(accessMethodId);
138+
(void) tableam_reloptions(tableam, RELKIND_TOASTVALUE, toast_options, NULL, true);
139+
}
129140

130141
NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
131142

0 commit comments

Comments
 (0)