From 1af0668abbb194beb88944e9608f2142b9279976 Mon Sep 17 00:00:00 2001 From: Nikita Malakhov Date: Sat, 14 Jun 2025 21:02:50 +0300 Subject: [PATCH] Custom reloptions for Table AM Currently custom reloptions could be set by Index AM, but not Table AM. This patch introduces possibility to define reloptions procedure like the it is introduced in Index AM, by adding .amoptions field to TableAmRoutine structure, and implementing function in the corresponding Table AM. The main scenario for using custom reloptions is creating table with custom options and table AM, as: CREATE TABLE t () USING myTableAM WITH (custom_opt1=..., ) and altering them with ALTER TABLE command. Author: Nikita Malakhov --- src/backend/access/common/reloptions.c | 7 ++-- src/backend/access/heap/heapam_handler.c | 3 +- src/backend/commands/createas.c | 2 +- src/backend/commands/tablecmds.c | 43 ++++++++++++++++++++++-- src/backend/tcop/utility.c | 3 +- src/include/access/reloptions.h | 2 +- src/include/access/tableam.h | 3 +- 7 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 50747c16396..eae86fea409 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -1419,7 +1419,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: - options = heap_reloptions(classForm->relkind, datum, false); + options = heap_reloptions(amoptions, classForm->relkind, datum, false); break; case RELKIND_PARTITIONED_TABLE: options = partitioned_table_reloptions(datum, false); @@ -2052,7 +2052,7 @@ 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(amoptions_function amoptions, char relkind, Datum reloptions, bool validate) { StdRdOptions *rdopts; @@ -2071,6 +2071,9 @@ heap_reloptions(char relkind, Datum reloptions, bool validate) return (bytea *) rdopts; case RELKIND_RELATION: case RELKIND_MATVIEW: + if(amoptions) + return amoptions(reloptions, validate); + return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); default: /* other relkinds are not supported */ diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index cb4bc35c93e..800eb81ae72 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2668,7 +2668,8 @@ static const TableAmRoutine heapam_methods = { .scan_bitmap_next_tuple = heapam_scan_bitmap_next_tuple, .scan_sample_next_block = heapam_scan_sample_next_block, - .scan_sample_next_tuple = heapam_scan_sample_next_tuple + .scan_sample_next_tuple = heapam_scan_sample_next_tuple, + .amoptions = NULL }; diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index dfd2ab8e862..97df562d244 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -127,7 +127,7 @@ create_ctas_internal(List *attrList, IntoClause *into) validnsps, true, false); - (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); + (void) heap_reloptions(NULL, 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 ea96947d813..7587a56fa1f 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -941,7 +941,41 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, (void) partitioned_table_reloptions(reloptions, true); break; default: - (void) heap_reloptions(relkind, reloptions, true); + TableAmRoutine *amroutine = NULL; + + 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); + } + + if(OidIsValid(accessMethodId) && accessMethodId != HEAP_TABLE_AM_OID) + { + HeapTuple tup; + + tup = SearchSysCache1(AMOID, + ObjectIdGetDatum(accessMethodId)); + if (HeapTupleIsValid(tup)) + { + Form_pg_am amform = (Form_pg_am) GETSTRUCT(tup); + + amroutine = unconstify(TableAmRoutine *, GetTableAmRoutine(amform->amhandler)); + + ReleaseSysCache(tup); + } + } + (void) heap_reloptions(amroutine ? amroutine->amoptions : NULL, relkind, reloptions, true); } if (stmt->ofTypename) @@ -16633,7 +16667,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, { case RELKIND_RELATION: case RELKIND_MATVIEW: - (void) heap_reloptions(rel->rd_rel->relkind, newOptions, true); + (void) heap_reloptions(rel->rd_tableam->amoptions, rel->rd_rel->relkind, newOptions, true); break; case RELKIND_PARTITIONED_TABLE: (void) partitioned_table_reloptions(newOptions, true); @@ -16751,7 +16785,10 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, newOptions = transformRelOptions(datum, defList, "toast", validnsps, false, operation == AT_ResetRelOptions); - (void) heap_reloptions(RELKIND_TOASTVALUE, newOptions, true); + /* Probably we have to always set NULL custom reloptions to TOAST tables? + * (void) heap_reloptions(NULL, RELKIND_TOASTVALUE, newOptions, true); + */ + (void) heap_reloptions(rel->rd_tableam->amoptions, RELKIND_TOASTVALUE, newOptions, true); memset(repl_val, 0, sizeof(repl_val)); memset(repl_null, false, sizeof(repl_null)); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 25fe3d58016..2454a4e66f8 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1188,7 +1188,8 @@ ProcessUtilitySlow(ParseState *pstate, validnsps, true, false); - (void) heap_reloptions(RELKIND_TOASTVALUE, + + (void) heap_reloptions(NULL, RELKIND_TOASTVALUE, toast_options, true); diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index dfbb4c85460..b8ba793cc8a 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -248,7 +248,7 @@ extern void *build_local_reloptions(local_relopts *relopts, Datum options, 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(amoptions_function amoptions, char relkind, Datum reloptions, 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 8713e12cbfb..97573931bb2 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -17,6 +17,7 @@ #ifndef TABLEAM_H #define TABLEAM_H +#include "access/amapi.h" #include "access/relscan.h" #include "access/sdir.h" #include "access/xact.h" @@ -834,7 +835,7 @@ typedef struct TableAmRoutine bool (*scan_sample_next_tuple) (TableScanDesc scan, struct SampleScanState *scanstate, TupleTableSlot *slot); - + amoptions_function amoptions; } TableAmRoutine; -- 2.34.1