commit 5c5c472e3fe40f8bb71e2727327bf3a070dba031 Author: Hao Wu Date: Fri May 5 09:13:22 2023 +0800 Add reloption support for table diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 41bf950a4a..c7f130acd3 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -973,7 +973,7 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) * reloptions processor for BRIN indexes */ bytea * -brinoptions(Datum reloptions, bool validate) +brinoptions(Datum reloptions, char relkind, bool validate) { static const relopt_parse_elt tab[] = { {"pages_per_range", RELOPT_TYPE_INT, offsetof(BrinOptions, pagesPerRange)}, diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 90cb3951fc..eed9521827 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -1401,7 +1401,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_MATVIEW: - options = heap_reloptions(classForm->relkind, datum, false); + options = table_reloptions(amoptions, datum, classForm->relkind, false); break; case RELKIND_PARTITIONED_TABLE: options = partitioned_table_reloptions(datum, false); @@ -1411,7 +1411,7 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, break; case RELKIND_INDEX: case RELKIND_PARTITIONED_INDEX: - options = index_reloptions(amoptions, datum, false); + options = index_reloptions(amoptions, datum, classForm->relkind, false); break; case RELKIND_FOREIGN_TABLE: options = NULL; @@ -2014,37 +2014,43 @@ view_reloptions(Datum reloptions, bool validate) tab, lengthof(tab)); } -/* - * Parse options for heaps, views and toast tables. - */ bytea * -heap_reloptions(char relkind, Datum reloptions, bool validate) +table_reloptions(amoptions_function amoptions, Datum reloptions, char relkind, bool validate) +{ + Assert(relkind == RELKIND_RELATION || + relkind == RELKIND_TOASTVALUE || + relkind == RELKIND_MATVIEW); + if (amoptions == NULL) + { + if (PointerIsValid(DatumGetPointer(reloptions))) + elog(ERROR, "table access method doesn't supported reloptions"); + return NULL; + } + return amoptions(reloptions, relkind, validate); +} + +bytea * +table_reloptions_am(Oid accessMethodId, Datum reloptions, char relkind, bool validate) { - StdRdOptions *rdopts; + const TableAmRoutine *tam; - switch (relkind) + Assert(relkind == RELKIND_RELATION || + relkind == RELKIND_TOASTVALUE || + relkind == RELKIND_MATVIEW); + + switch(accessMethodId) { - case RELKIND_TOASTVALUE: - rdopts = (StdRdOptions *) - default_reloptions(reloptions, validate, RELOPT_KIND_TOAST); - if (rdopts != NULL) - { - /* adjust default-only parameters for TOAST relations */ - rdopts->fillfactor = 100; - rdopts->autovacuum.analyze_threshold = -1; - rdopts->autovacuum.analyze_scale_factor = -1; - } - return (bytea *) rdopts; - case RELKIND_RELATION: - case RELKIND_MATVIEW: - return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); + /* built-in table access method put here to fetch TAM fast */ + case HEAP_TABLE_AM_OID: + tam = GetHeapamTableAmRoutine(); + break; default: - /* other relkinds are not supported */ - return NULL; + tam = GetTableAmRoutineByAmId(accessMethodId); + break; } + return table_reloptions(tam->amoptions, reloptions, relkind, validate); } - /* * Parse options for indexes. * @@ -2053,7 +2059,7 @@ heap_reloptions(char relkind, Datum reloptions, bool validate) * validate error flag */ bytea * -index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate) +index_reloptions(amoptions_function amoptions, Datum reloptions, char relkind, bool validate) { Assert(amoptions != NULL); @@ -2061,7 +2067,7 @@ index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate) if (!PointerIsValid(DatumGetPointer(reloptions))) return NULL; - return amoptions(reloptions, validate); + return amoptions(reloptions, relkind, validate); } /* diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 437f24753c..7cdaf3c6f9 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -598,7 +598,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum, } bytea * -ginoptions(Datum reloptions, bool validate) +ginoptions(Datum reloptions, char relkind, bool validate) { static const relopt_parse_elt tab[] = { {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)}, diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index f9f51152b8..cc21368c45 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -909,7 +909,7 @@ gistPageRecyclable(Page page) } bytea * -gistoptions(Datum reloptions, bool validate) +gistoptions(Datum reloptions, char relkind, bool validate) { static const relopt_parse_elt tab[] = { {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)}, diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 88089ce02b..638cb901c4 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -273,7 +273,7 @@ _hash_checkpage(Relation rel, Buffer buf, int flags) } bytea * -hashoptions(Datum reloptions, bool validate) +hashoptions(Datum reloptions, char relkind, bool validate) { static const relopt_parse_elt tab[] = { {"fillfactor", RELOPT_TYPE_INT, offsetof(HashOptions, fillfactor)}, diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index cbb35aa73d..d0adc674e2 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" @@ -2539,6 +2540,36 @@ SampleHeapTupleVisible(TableScanDesc scan, Buffer buffer, } } +/* + * Parse options for heaps, views and toast tables. + */ +static bytea * +heapam_amoptions(Datum reloptions, char relkind, bool validate) +{ + StdRdOptions *rdopts; + + switch (relkind) + { + case RELKIND_TOASTVALUE: + rdopts = (StdRdOptions *) + default_reloptions(reloptions, validate, RELOPT_KIND_TOAST); + if (rdopts != NULL) + { + /* adjust default-only parameters for TOAST relations */ + rdopts->fillfactor = 100; + rdopts->autovacuum.analyze_threshold = -1; + rdopts->autovacuum.analyze_scale_factor = -1; + } + return (bytea *) rdopts; + case RELKIND_RELATION: + case RELKIND_MATVIEW: + return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); + default: + Assert(false); + return NULL; + } +} + /* ------------------------------------------------------------------------ * Definition of the heap table access method. @@ -2601,7 +2632,10 @@ static const TableAmRoutine heapam_methods = { .scan_bitmap_next_block = heapam_scan_bitmap_next_block, .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 = heapam_amoptions, + }; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 05abf36032..5ba16b6bb6 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -2109,7 +2109,7 @@ BTreeShmemInit(void) } bytea * -btoptions(Datum reloptions, bool validate) +btoptions(Datum reloptions, char relkind, bool validate) { static const relopt_parse_elt tab[] = { {"fillfactor", RELOPT_TYPE_INT, offsetof(BTOptions, fillfactor)}, diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 190e4f76a9..ecf8af32ac 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -728,7 +728,7 @@ SpGistInitMetapage(Page page) * reloptions processing for SPGiST */ bytea * -spgoptions(Datum reloptions, bool validate) +spgoptions(Datum reloptions, char relkind, bool validate) { static const relopt_parse_elt tab[] = { {"fillfactor", RELOPT_TYPE_INT, offsetof(SpGistOptions, fillfactor)}, diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c index d7798b6afb..0392ba7842 100644 --- a/src/backend/access/table/tableamapi.c +++ b/src/backend/access/table/tableamapi.c @@ -107,6 +107,36 @@ GetTableAmRoutine(Oid amhandler) return routine; } +/* + * GetTableAmRoutineByAmId - look up the handler of the table access method + * with the given OID, and get its TableAmRoutine struct. + * + * If the given OID isn't a valid index access method, throws error. + */ +const TableAmRoutine * +GetTableAmRoutineByAmId(Oid amoid) +{ + HeapTuple tuple; + Form_pg_am amform; + regproc amhandler; + + tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, (errmsg("cache lookup failed for access method %u", amoid))); + + amform = (Form_pg_am) GETSTRUCT(tuple); + if (amform->amtype != AMTYPE_TABLE) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("access method \"%s\" is not of type TABLE", + NameStr(amform->amname)))); + + amhandler = amform->amhandler; + ReleaseSysCache(tuple); + + return GetTableAmRoutine(amhandler); +} + /* 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/catalog/toasting.c b/src/backend/catalog/toasting.c index ab12b0b9de..291a556c71 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -15,6 +15,7 @@ #include "postgres.h" #include "access/heapam.h" +#include "access/reloptions.h" #include "access/toast_compression.h" #include "access/xact.h" #include "catalog/binary_upgrade.h" @@ -148,6 +149,11 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, ObjectAddress baseobject, toastobject; + Assert(rel->rd_tableam || rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); + if (rel->rd_tableam) + (void) table_reloptions_am(table_relation_toast_am(rel), reloptions, + RELKIND_TOASTVALUE, true); + /* * Is it already toasted? */ diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c index e91920ca14..9183f7258e 100644 --- a/src/backend/commands/createas.c +++ b/src/backend/commands/createas.c @@ -130,8 +130,6 @@ create_ctas_internal(List *attrList, IntoClause *into) validnsps, true, false); - (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); - NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options); /* Create the "view" part of a materialized view. */ diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index e6ee99e51f..5b8c4b1358 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -887,7 +887,7 @@ DefineIndex(Oid relationId, reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, NULL, false, false); - (void) index_reloptions(amoptions, reloptions, true); + (void) index_reloptions(amoptions, reloptions, RELKIND_INDEX, true); /* * Prepare arguments for index_create, primarily an IndexInfo structure. diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index c7a8a689b7..e874ba9778 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -822,6 +822,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. */ @@ -836,8 +856,13 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, case RELKIND_PARTITIONED_TABLE: (void) partitioned_table_reloptions(reloptions, true); break; + case RELKIND_RELATION: + case RELKIND_MATVIEW: + case RELKIND_TOASTVALUE: + (void) table_reloptions_am(accessMethodId, reloptions, relkind, true); + break; default: - (void) heap_reloptions(relkind, reloptions, true); + break; } if (stmt->ofTypename) @@ -941,26 +966,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, attr->attstorage = GetAttributeStorage(attr->atttypid, colDef->storage_name); } - /* - * 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 @@ -14333,7 +14338,7 @@ 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->rd_tableam->amoptions, newOptions, rel->rd_rel->relkind, true); break; case RELKIND_PARTITIONED_TABLE: (void) partitioned_table_reloptions(newOptions, true); @@ -14343,7 +14348,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, break; case RELKIND_INDEX: case RELKIND_PARTITIONED_INDEX: - (void) index_reloptions(rel->rd_indam->amoptions, newOptions, true); + (void) index_reloptions(rel->rd_indam->amoptions, newOptions, rel->rd_rel->relkind, true); break; default: ereport(ERROR, @@ -14446,7 +14451,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(toastrel->rd_tableam->amoptions, newOptions, RELKIND_TOASTVALUE, 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 30b51bf4d3..35989558ad 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1195,9 +1195,6 @@ ProcessUtilitySlow(ParseState *pstate, validnsps, true, false); - (void) heap_reloptions(RELKIND_TOASTVALUE, - toast_options, - true); NewRelationCreateToastTable(address.objectId, toast_options); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 40140de958..20e80c24e7 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -474,8 +474,10 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple) { case RELKIND_RELATION: case RELKIND_TOASTVALUE: - case RELKIND_VIEW: case RELKIND_MATVIEW: + amoptsfn = relation->rd_tableam->amoptions; + break; + case RELKIND_VIEW: case RELKIND_PARTITIONED_TABLE: amoptsfn = NULL; break; diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index 281039ef67..389a74fbc3 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -138,6 +138,7 @@ typedef void (*amcostestimate_function) (struct PlannerInfo *root, /* parse index reloptions */ typedef bytea *(*amoptions_function) (Datum reloptions, + char relkind, bool validate); /* report AM, index, or index column property */ diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h index 97ddc925b2..1caf7c73c7 100644 --- a/src/include/access/brin_internal.h +++ b/src/include/access/brin_internal.h @@ -107,7 +107,7 @@ extern IndexBulkDeleteResult *brinbulkdelete(IndexVacuumInfo *info, void *callback_state); extern IndexBulkDeleteResult *brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats); -extern bytea *brinoptions(Datum reloptions, bool validate); +extern bytea *brinoptions(Datum reloptions, char relkind, bool validate); /* brin_validate.c */ extern bool brinvalidate(Oid opclassoid); diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 6da64928b6..bb68423abe 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -89,7 +89,7 @@ typedef struct GinState /* ginutil.c */ -extern bytea *ginoptions(Datum reloptions, bool validate); +extern bytea *ginoptions(Datum reloptions, char relkind, bool validate); extern void initGinState(GinState *state, Relation index); extern Buffer GinNewBuffer(Relation index); extern void GinInitBuffer(Buffer b, uint32 f); diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index ee275650bd..658da14b33 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -479,7 +479,7 @@ extern void gistadjustmembers(Oid opfamilyoid, #define GIST_MIN_FILLFACTOR 10 #define GIST_DEFAULT_FILLFACTOR 90 -extern bytea *gistoptions(Datum reloptions, bool validate); +extern bytea *gistoptions(Datum reloptions, char relkind, bool validate); extern bool gistproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull); diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 9e035270a1..d71441ff25 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -380,7 +380,7 @@ extern IndexBulkDeleteResult *hashbulkdelete(IndexVacuumInfo *info, void *callback_state); extern IndexBulkDeleteResult *hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats); -extern bytea *hashoptions(Datum reloptions, bool validate); +extern bytea *hashoptions(Datum reloptions, char relkind, bool validate); extern bool hashvalidate(Oid opclassoid); extern void hashadjustmembers(Oid opfamilyoid, Oid opclassoid, diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index d684786095..8547c6a806 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -1260,7 +1260,7 @@ extern void _bt_end_vacuum(Relation rel); extern void _bt_end_vacuum_callback(int code, Datum arg); extern Size BTreeShmemSize(void); extern void BTreeShmemInit(void); -extern bytea *btoptions(Datum reloptions, bool validate); +extern bytea *btoptions(Datum reloptions, char relkind, bool validate); extern bool btproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull); diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1d5bfa62ff..9ba57cb5d5 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -235,11 +235,15 @@ 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 *table_reloptions(amoptions_function amoptions, Datum reloptions, + char relkind, bool validate); +extern bytea *table_reloptions_am(Oid accessMethodId, Datum reloptions, + char relkind, 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, - bool validate); + char relkind, bool validate); extern bytea *attribute_reloptions(Datum reloptions, bool validate); extern bytea *tablespace_reloptions(Datum reloptions, bool validate); extern LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList); diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index fe31d32dbe..9ceba400c8 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -190,7 +190,7 @@ typedef struct spgLeafConsistentOut /* spgutils.c */ -extern bytea *spgoptions(Datum reloptions, bool validate); +extern bytea *spgoptions(Datum reloptions, char relkind, bool validate); /* spginsert.c */ extern IndexBuildResult *spgbuild(Relation heap, Relation index, diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index b19d50ecc2..681d872cb8 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -866,6 +866,11 @@ typedef struct TableAmRoutine struct SampleScanState *scanstate, TupleTableSlot *slot); + /* + * This callback is used to parse reloptions for relation/matview/toast. + */ + bytea *(*amoptions)(Datum reloptions, char relkind, bool validate); + } TableAmRoutine; @@ -2095,6 +2100,7 @@ extern void table_block_relation_estimate_size(Relation rel, */ extern const TableAmRoutine *GetTableAmRoutine(Oid amhandler); +extern const TableAmRoutine *GetTableAmRoutineByAmId(Oid amoid); extern const TableAmRoutine *GetHeapamTableAmRoutine(void); #endif /* TABLEAM_H */