0007-Custom-reloptions-for-table-AM-v4.patch
application/octet-stream
Filename: 0007-Custom-reloptions-for-table-AM-v4.patch
Type: application/octet-stream
Part: 7
Message:
Re: Table AM Interface Enhancements
Patch
Format: format-patch
Series: patch v4-0007
Subject: Custom reloptions for table AM
| File | + | − |
|---|---|---|
| src/backend/access/common/reloptions.c | 4 | 2 |
| src/backend/access/heap/heapam_handler.c | 13 | 0 |
| src/backend/access/table/tableamapi.c | 20 | 0 |
| src/backend/commands/tablecmds.c | 30 | 21 |
| src/backend/postmaster/autovacuum.c | 3 | 1 |
| src/backend/utils/cache/relcache.c | 5 | 1 |
| src/include/access/reloptions.h | 2 | 0 |
| src/include/access/tableam.h | 29 | 0 |
From 1fb3470d80609405ad6c1d60b6311a9a10ee4938 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Mon, 12 Jun 2023 23:16:01 +0300
Subject: [PATCH 07/13] Custom reloptions for table AM
Let table AM define custom reloptions for its tables.
---
src/backend/access/common/reloptions.c | 6 ++-
src/backend/access/heap/heapam_handler.c | 13 ++++++
src/backend/access/table/tableamapi.c | 20 ++++++++++
src/backend/commands/tablecmds.c | 51 ++++++++++++++----------
src/backend/postmaster/autovacuum.c | 4 +-
src/backend/utils/cache/relcache.c | 6 ++-
src/include/access/reloptions.h | 2 +
src/include/access/tableam.h | 29 ++++++++++++++
8 files changed, 106 insertions(+), 25 deletions(-)
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index d6eb5d85599..963995388bb 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"
@@ -1377,7 +1378,7 @@ untransformRelOptions(Datum options)
*/
bytea *
extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
- amoptions_function amoptions)
+ const TableAmRoutine *tableam, amoptions_function amoptions)
{
bytea *options;
bool isnull;
@@ -1399,7 +1400,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, false);
break;
case RELKIND_PARTITIONED_TABLE:
options = partitioned_table_reloptions(datum, false);
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 5d125aad6bc..14e0952d7f2 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -25,6 +25,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"
@@ -2427,6 +2428,17 @@ heapam_relation_toast_am(Relation rel)
return rel->rd_rel->relam;
}
+static bytea *
+heapam_reloptions(char relkind, Datum reloptions, bool validate)
+{
+ if (relkind == RELKIND_RELATION ||
+ relkind == RELKIND_TOASTVALUE ||
+ relkind == RELKIND_MATVIEW)
+ return heap_reloptions(relkind, reloptions, validate);
+
+ return NULL;
+}
+
/* ------------------------------------------------------------------------
* Planner related callbacks for the heap AM
@@ -2932,6 +2944,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/table/tableamapi.c b/src/backend/access/table/tableamapi.c
index 55b8caeadf2..34ff3e38333 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,24 @@ GetTableAmRoutine(Oid amhandler)
return routine;
}
+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/tablecmds.c b/src/backend/commands/tablecmds.c
index 3ed0618b4e6..d2ef8a0c383 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -705,6 +705,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
LOCKMODE parentLockmode;
const char *accessMethod = NULL;
Oid accessMethodId = InvalidOid;
+ const TableAmRoutine *tableam = NULL;
/*
* Truncate relname to appropriate length (probably a waste of time, as
@@ -844,6 +845,26 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
if (!OidIsValid(ownerId))
ownerId = GetUserId();
+ /*
+ * If the statement hasn't specified an access method, but we're defining
+ * a type of relation that needs one, use the default.
+ */
+ if (stmt->accessMethod != NULL)
+ {
+ accessMethod = stmt->accessMethod;
+
+ if (partitioned)
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("specifying a table access method is not supported on a partitioned table")));
+ }
+ else if (RELKIND_HAS_TABLE_AM(relkind))
+ accessMethod = default_table_access_method;
+
+ /* look up the access method, verify it is for a table */
+ if (accessMethod != NULL)
+ accessMethodId = get_table_am_oid(accessMethod, false);
+
/*
* Parse and validate reloptions, if any.
*/
@@ -852,6 +873,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, true);
+ break;
case RELKIND_VIEW:
(void) view_reloptions(reloptions, true);
break;
@@ -860,6 +887,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
break;
default:
(void) heap_reloptions(relkind, reloptions, true);
+ break;
}
if (stmt->ofTypename)
@@ -951,26 +979,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
}
}
- /*
- * If the statement hasn't specified an access method, but we're defining
- * a type of relation that needs one, use the default.
- */
- if (stmt->accessMethod != NULL)
- {
- accessMethod = stmt->accessMethod;
-
- if (partitioned)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("specifying a table access method is not supported on a partitioned table")));
- }
- else if (RELKIND_HAS_TABLE_AM(relkind))
- accessMethod = default_table_access_method;
-
- /* look up the access method, verify it is for a table */
- if (accessMethod != NULL)
- accessMethodId = get_table_am_oid(accessMethod, false);
-
/*
* Create the relation. Inherited defaults and constraints are passed in
* for immediate handling --- since they don't need parsing, they can be
@@ -15309,7 +15317,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, true);
break;
case RELKIND_PARTITIONED_TABLE:
(void) partitioned_table_reloptions(newOptions, true);
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 71e8a6f2584..d1d76016ab4 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2661,7 +2661,9 @@ extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_MATVIEW ||
((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
- relopts = extractRelOptions(tup, pg_class_desc, NULL);
+ relopts = extractRelOptions(tup, pg_class_desc,
+ GetTableAmRoutineByAmOid(((Form_pg_class) GETSTRUCT(tup))->relam),
+ NULL);
if (relopts == NULL)
return NULL;
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 6d98bdfba06..3babfc804a7 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"
@@ -465,6 +466,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
{
bytea *options;
amoptions_function amoptsfn;
+ const TableAmRoutine *tableam = NULL;
relation->rd_options = NULL;
@@ -479,6 +481,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:
@@ -494,7 +497,8 @@ 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);
/*
* Copy parsed data into CacheMemoryContext. To guard against the
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 81829b8270a..8ddc75df287 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,6 +225,7 @@ extern Datum transformRelOptions(Datum oldOptions, List *defList,
bool acceptOidsOff, bool isReset);
extern List *untransformRelOptions(Datum options);
extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
+ const TableAmRoutine *tableam,
amoptions_function amoptions);
extern void *build_reloptions(Datum reloptions, bool validate,
relopt_kind kind,
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 5f3c7f865ef..15bca56f054 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -739,6 +739,11 @@ typedef struct TableAmRoutine
int32 slicelength,
struct varlena *result);
+ /*
+ * Parse table AM-specific table options.
+ */
+ bytea *(*reloptions) (char relkind, Datum reloptions, bool validate);
+
/* ------------------------------------------------------------------------
* Planner related functions.
@@ -1935,6 +1940,29 @@ table_relation_fetch_toast_slice(Relation toastrel, Oid valueid,
result);
}
+/*
+ * Parse options for given table.
+ */
+static inline bytea *
+table_reloptions(Relation rel, char relkind,
+ Datum reloptions, bool validate)
+{
+ return rel->rd_tableam->reloptions(relkind, reloptions, validate);
+}
+
+/*
+ * Parse table options without knowledge of particular table.
+ */
+static inline bytea *
+tableam_reloptions(const TableAmRoutine *tableam, char relkind,
+ Datum reloptions, bool validate)
+{
+ return tableam->reloptions(relkind, reloptions, validate);
+}
+
+extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
+ bool validate);
+
/* ----------------------------------------------------------------------------
* Planner related functionality
@@ -2112,6 +2140,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
--
2.39.3 (Apple Git-145)