On Tue, Feb 09, 2021 at 04:27:34PM +0900, Michael Paquier wrote: > Putting sanity checks within all the table_* functions of tableam.h > would not be a good idea, as nothing prevents the call of what's > stored in rel->rd_tableam.
I have been playing with this idea, and finished with the attached, which is not the sexiest patch around. The table AM used as fallback for tables without storage is called no_storage (this could be called virtual_am?). Reverting e786be5 or dd705a0 leads to an error coming from no_storage instead of a crash. One thing to note is that this simplifies a bit slot_callbacks as views, foreign tables and partitioned tables can grab their slot type directly from this new table AM. -- Michael
From 0611ef60b39907a3bd405ece990d661d4d63900d Mon Sep 17 00:00:00 2001 From: Michael Paquier <mich...@paquier.xyz> Date: Mon, 15 Feb 2021 16:21:01 +0900 Subject: [PATCH] Add no_storage, fallback table AM for relations without storage --- src/include/access/tableam.h | 6 +- src/include/catalog/pg_am.dat | 4 + src/include/catalog/pg_proc.dat | 4 + src/backend/access/Makefile | 5 +- src/backend/access/no_storage/Makefile | 18 + src/backend/access/no_storage/README | 9 + .../access/no_storage/no_storage_handler.c | 518 ++++++++++++++++++ src/backend/access/table/tableam.c | 33 -- src/backend/utils/cache/relcache.c | 37 +- src/test/regress/expected/create_am.out | 11 +- src/test/regress/expected/psql.out | 96 ++-- 11 files changed, 639 insertions(+), 102 deletions(-) create mode 100644 src/backend/access/no_storage/Makefile create mode 100644 src/backend/access/no_storage/README create mode 100644 src/backend/access/no_storage/no_storage_handler.c diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h index 33bffb6815..999e05bb89 100644 --- a/src/include/access/tableam.h +++ b/src/include/access/tableam.h @@ -832,7 +832,11 @@ typedef struct TableAmRoutine * for the relation. Works for tables, views, foreign tables and partitioned * tables. */ -extern const TupleTableSlotOps *table_slot_callbacks(Relation rel); +static inline const TupleTableSlotOps * +table_slot_callbacks(Relation rel) +{ + return rel->rd_tableam->slot_callbacks(rel); +} /* * Returns slot using the callbacks returned by table_slot_callbacks(), and diff --git a/src/include/catalog/pg_am.dat b/src/include/catalog/pg_am.dat index 6082f0e6a8..e0e32a681f 100644 --- a/src/include/catalog/pg_am.dat +++ b/src/include/catalog/pg_am.dat @@ -15,6 +15,10 @@ { oid => '2', oid_symbol => 'HEAP_TABLE_AM_OID', descr => 'heap table access method', amname => 'heap', amhandler => 'heap_tableam_handler', amtype => 't' }, +{ oid => '8381', oid_symbol => 'NO_STORAGE_TABLE_AM_OID', + descr => 'no_storage table access method', + amname => 'no_storage', amhandler => 'no_storage_tableam_handler', + amtype => 't' }, { oid => '403', oid_symbol => 'BTREE_AM_OID', descr => 'b-tree index access method', amname => 'btree', amhandler => 'bthandler', amtype => 'i' }, diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 4e0c9be58c..5a796324a5 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -905,6 +905,10 @@ proname => 'heap_tableam_handler', provolatile => 'v', prorettype => 'table_am_handler', proargtypes => 'internal', prosrc => 'heap_tableam_handler' }, +{ oid => '8382', descr => 'no_storage access method handler', + proname => 'no_storage_tableam_handler', provolatile => 'v', + prorettype => 'table_am_handler', proargtypes => 'internal', + prosrc => 'no_storage_tableam_handler' }, # Index access method handlers { oid => '330', descr => 'btree index access method handler', diff --git a/src/backend/access/Makefile b/src/backend/access/Makefile index 0880e0a8bb..29d3937ada 100644 --- a/src/backend/access/Makefile +++ b/src/backend/access/Makefile @@ -8,7 +8,8 @@ subdir = src/backend/access top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -SUBDIRS = brin common gin gist hash heap index nbtree rmgrdesc spgist \ - table tablesample transam +SUBDIRS = brin common gin gist hash heap index nbtree no_storage \ + rmgrdesc spgist \ + table tablesample transam include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/access/no_storage/Makefile b/src/backend/access/no_storage/Makefile new file mode 100644 index 0000000000..8d1227b428 --- /dev/null +++ b/src/backend/access/no_storage/Makefile @@ -0,0 +1,18 @@ +#------------------------------------------------------------------------- +# +# Makefile-- +# Makefile for access/no_storage +# +# IDENTIFICATION +# src/backend/access/no_storage/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/backend/access/no_storage +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global + +OBJS = \ + no_storage_handler.o + +include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/access/no_storage/README b/src/backend/access/no_storage/README new file mode 100644 index 0000000000..cb1d97fa0e --- /dev/null +++ b/src/backend/access/no_storage/README @@ -0,0 +1,9 @@ +src/backend/access/no_storage/README + +No-Storage Table Access method +============================== + +no_storage is a table access method used as a default fallback for relation +types that have no physical storage, issuing an error if there is an attempt +to access this layer of the system. This prevents rd_tableam to be NULL for +a relation cache entry. diff --git a/src/backend/access/no_storage/no_storage_handler.c b/src/backend/access/no_storage/no_storage_handler.c new file mode 100644 index 0000000000..00eee46b2d --- /dev/null +++ b/src/backend/access/no_storage/no_storage_handler.c @@ -0,0 +1,518 @@ +/*------------------------------------------------------------------------- + * + * no_storage_handler.c + * no_storage table access method code + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/access/no_storage/no_storage_handler.c + * + * + * NOTES + * This file introduces the table access method no_storage, that is + * used as a fallback implementation for relation types without + * storage. Most of the callbacks defined in this file would lead + * to failures for operations not authorized on such relations. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <math.h> + +#include "miscadmin.h" + +#include "access/tableam.h" +#include "access/heapam.h" +#include "access/amapi.h" +#include "catalog/index.h" +#include "commands/vacuum.h" +#include "executor/tuptable.h" +#include "utils/fmgrprotos.h" + +static const TableAmRoutine no_storage_methods; + + +/* ------------------------------------------------------------------------ + * Slot related callbacks for no_storage AM + * ------------------------------------------------------------------------ + */ + +static const TupleTableSlotOps * +no_storage_slot_callbacks(Relation relation) +{ + if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE) + { + /* + * Historically FDWs expect to store heap tuples in slots. Continue + * handing them one, to make it less painful to adapt FDWs to new + * versions. The cost of a heap slot over a virtual slot is pretty + * small. + */ + return &TTSOpsHeapTuple; + } + + /* + * These need to be supported, as some parts of the code (like COPY) need + * to create slots for such relations too. It seems better to centralize + * the knowledge that a heap slot is the right thing in that case here. + */ + if (relation->rd_rel->relkind != RELKIND_VIEW && + relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE) + elog(ERROR, "no_storage_slot_callbacks() failed on relation \"%s\"", + RelationGetRelationName(relation)); + return &TTSOpsVirtual; +} + +/* ------------------------------------------------------------------------ + * Table Scan Callbacks for no_storage AM + * ------------------------------------------------------------------------ + */ + +static TableScanDesc +no_storage_scan_begin(Relation relation, Snapshot snapshot, + int nkeys, ScanKey key, + ParallelTableScanDesc parallel_scan, + uint32 flags) +{ + elog(ERROR, "no_storage_scan_begin() failed on relation \"%s\"", + RelationGetRelationName(relation)); + return NULL; +} + +static void +no_storage_scan_end(TableScanDesc sscan) +{ + elog(ERROR, "no_storage_scan_end() failed"); +} + +static void +no_storage_scan_rescan(TableScanDesc sscan, ScanKey key, bool set_params, + bool allow_strat, bool allow_sync, bool allow_pagemode) +{ + elog(ERROR, "no_storage_scan_rescan() failed"); +} + +static bool +no_storage_scan_getnextslot(TableScanDesc sscan, ScanDirection direction, + TupleTableSlot *slot) +{ + elog(ERROR, "no_storage_scan_getnextslot() failed"); + return false; /* keep compiler quiet */ +} + +/* ------------------------------------------------------------------------ + * Index Scan Callbacks for no_storage AM + * ------------------------------------------------------------------------ + */ + +static IndexFetchTableData * +no_storage_index_fetch_begin(Relation rel) +{ + elog(ERROR, "no_storage_index_fetch_begin() failed on relation \"%s\"", + RelationGetRelationName(rel)); + return NULL; +} + +static void +no_storage_index_fetch_reset(IndexFetchTableData *scan) +{ + elog(ERROR, "no_storage_index_fetch_reset() failed"); +} + +static void +no_storage_index_fetch_end(IndexFetchTableData *scan) +{ + elog(ERROR, "no_storage_index_fetch_end() failed"); +} + +static bool +no_storage_index_fetch_tuple(struct IndexFetchTableData *scan, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot, + bool *call_again, bool *all_dead) +{ + elog(ERROR, "no_storage_index_fetch_tuple() failed"); + return 0; +} + + +/* ------------------------------------------------------------------------ + * Callbacks for non-modifying operations on individual tuples for + * no_storage AM. + * ------------------------------------------------------------------------ + */ + +static bool +no_storage_fetch_row_version(Relation relation, + ItemPointer tid, + Snapshot snapshot, + TupleTableSlot *slot) +{ + elog(ERROR, "no_storage_fetch_row_version() failed"); + return false; +} + +static void +no_storage_get_latest_tid(TableScanDesc sscan, + ItemPointer tid) +{ + elog(ERROR, "no_storage_get_latest_tid() failed"); +} + +static bool +no_storage_tuple_tid_valid(TableScanDesc scan, ItemPointer tid) +{ + elog(ERROR, "no_storage_tuple_tid_valid() failed"); + return false; +} + +static bool +no_storage_tuple_satisfies_snapshot(Relation rel, TupleTableSlot *slot, + Snapshot snapshot) +{ + elog(ERROR, "no_storage_tuple_satisfies_snapshot() failed on relation \"%s\"", + RelationGetRelationName(rel)); + return false; +} + +static TransactionId +no_storage_index_delete_tuples(Relation rel, + TM_IndexDeleteOp * delstate) +{ + elog(ERROR, "no_storage_index_delete_tuples() failed on relation \"%s\"", + RelationGetRelationName(rel)); + return InvalidTransactionId; +} + +/* ---------------------------------------------------------------------------- + * Functions for manipulations of physical tuples for no_storage AM. + * ---------------------------------------------------------------------------- + */ + +static void +no_storage_tuple_insert(Relation relation, TupleTableSlot *slot, + CommandId cid, int options, BulkInsertState bistate) +{ + elog(ERROR, "no_storage_tuple_insert() failed on relation \"%s\"", + RelationGetRelationName(relation)); +} + +static void +no_storage_tuple_insert_speculative(Relation relation, TupleTableSlot *slot, + CommandId cid, int options, + BulkInsertState bistate, + uint32 specToken) +{ + elog(ERROR, "no_storage_tuple_insert_speculative() failed on relation \"%s\"", + RelationGetRelationName(relation)); +} + +static void +no_storage_tuple_complete_speculative(Relation relation, TupleTableSlot *slot, + uint32 spekToken, bool succeeded) +{ + elog(ERROR, "no_storage_tuple_complete_speculative() failed on relation \"%s\"", + RelationGetRelationName(relation)); +} + +static void +no_storage_multi_insert(Relation relation, TupleTableSlot **slots, + int ntuples, CommandId cid, int options, + BulkInsertState bistate) +{ + elog(ERROR, "no_storage_multi_insert() failed on relation \"%s\"", + RelationGetRelationName(relation)); +} + +static TM_Result +no_storage_tuple_delete(Relation relation, ItemPointer tid, CommandId cid, + Snapshot snapshot, Snapshot crosscheck, bool wait, + TM_FailureData *tmfd, bool changingPart) +{ + elog(ERROR, "no_storage_tuple_delete() failed on relation \"%s\"", + RelationGetRelationName(relation)); + return TM_Ok; +} + + +static TM_Result +no_storage_tuple_update(Relation relation, ItemPointer otid, + TupleTableSlot *slot, CommandId cid, + Snapshot snapshot, Snapshot crosscheck, + bool wait, TM_FailureData *tmfd, + LockTupleMode *lockmode, bool *update_indexes) +{ + elog(ERROR, "no_storage_tuple_update() failed on relation \"%s\"", + RelationGetRelationName(relation)); + return TM_Ok; +} + +static TM_Result +no_storage_tuple_lock(Relation relation, ItemPointer tid, Snapshot snapshot, + TupleTableSlot *slot, CommandId cid, LockTupleMode mode, + LockWaitPolicy wait_policy, uint8 flags, + TM_FailureData *tmfd) +{ + elog(ERROR, "no_storage_tuple_lock() failed on relation \"%s\"", + RelationGetRelationName(relation)); + return TM_Ok; +} + +static void +no_storage_finish_bulk_insert(Relation relation, int options) +{ + elog(ERROR, "no_storage_finish_bulk_insert() failed on relation \"%s\"", + RelationGetRelationName(relation)); +} + + +/* ------------------------------------------------------------------------ + * DDL related callbacks for no_storage AM. + * ------------------------------------------------------------------------ + */ + +static void +no_storage_relation_set_new_filenode(Relation rel, + const RelFileNode *newrnode, + char persistence, + TransactionId *freezeXid, + MultiXactId *minmulti) +{ + elog(ERROR, "no_storage_relation_set_new_filenode() failed on relation \"%s\"", + RelationGetRelationName(rel)); +} + +static void +no_storage_relation_nontransactional_truncate(Relation rel) +{ + elog(ERROR, "no_storage_relation_nontransactional_truncate() failed on relation \"%s\"", + RelationGetRelationName(rel)); +} + +static void +no_storage_copy_data(Relation rel, const RelFileNode *newrnode) +{ + elog(ERROR, "no_storage_copy_data() failed on relation \"%s\"", + RelationGetRelationName(rel)); +} + +static void +no_storage_copy_for_cluster(Relation OldTable, Relation NewTable, + Relation OldIndex, bool use_sort, + TransactionId OldestXmin, + TransactionId *xid_cutoff, + MultiXactId *multi_cutoff, + double *num_tuples, + double *tups_vacuumed, + double *tups_recently_dead) +{ + elog(ERROR, "no_storage_copy_for_cluster() failed on relation \"%s\"", + RelationGetRelationName(OldTable)); +} + +static void +no_storage_vacuum(Relation onerel, VacuumParams *params, + BufferAccessStrategy bstrategy) +{ + elog(ERROR, "no_storage_vacuum() failed on relation \"%s\"", + RelationGetRelationName(onerel)); +} + +static bool +no_storage_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno, + BufferAccessStrategy bstrategy) +{ + elog(ERROR, "no_storage_scan_analyze_next_block() failed"); + return false; +} + +static bool +no_storage_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin, + double *liverows, double *deadrows, + TupleTableSlot *slot) +{ + elog(ERROR, "no_storage_scan_analyze_next_tuple() failed"); + return false; +} + +static double +no_storage_index_build_range_scan(Relation tableRelation, + Relation indexRelation, + IndexInfo *indexInfo, + bool allow_sync, + bool anyvisible, + bool progress, + BlockNumber start_blockno, + BlockNumber numblocks, + IndexBuildCallback callback, + void *callback_state, + TableScanDesc scan) +{ + elog(ERROR, "no_storage_index_build_range_scan() failed on relation \"%s\"", + RelationGetRelationName(tableRelation)); + return 0; +} + +static void +no_storage_index_validate_scan(Relation tableRelation, + Relation indexRelation, + IndexInfo *indexInfo, + Snapshot snapshot, + ValidateIndexState *state) +{ + elog(ERROR, "no_storage_index_validate_scan() failed on relation \"%s\"", + RelationGetRelationName(tableRelation)); +} + + +/* ------------------------------------------------------------------------ + * Miscellaneous callbacks for the no_storage AM + * ------------------------------------------------------------------------ + */ + +static uint64 +no_storage_relation_size(Relation rel, ForkNumber forkNumber) +{ + elog(ERROR, "no_storage_relation_size() failed on relation \"%s\"", + RelationGetRelationName(rel)); + return 0; +} + +/* + * Check to see whether the table needs a TOAST table. + */ +static bool +no_storage_relation_needs_toast_table(Relation rel) +{ + elog(ERROR, "no_storage_relation_needs_toast_table() failed on relation \"%s\"", + RelationGetRelationName(rel)); + return false; +} + + +/* ------------------------------------------------------------------------ + * Planner related callbacks for the no_storage AM + * ------------------------------------------------------------------------ + */ + +static void +no_storage_estimate_rel_size(Relation rel, int32 *attr_widths, + BlockNumber *pages, double *tuples, + double *allvisfrac) +{ + elog(ERROR, "no_storage_estimate_rel_size() failed on relation \"%s\"", + RelationGetRelationName(rel)); +} + + +/* ------------------------------------------------------------------------ + * Executor related callbacks for the no_storage AM + * ------------------------------------------------------------------------ + */ + +static bool +no_storage_scan_bitmap_next_block(TableScanDesc scan, + TBMIterateResult *tbmres) +{ + elog(ERROR, "no_storage_scan_bitmap_next_block() failed"); + return false; +} + +static bool +no_storage_scan_bitmap_next_tuple(TableScanDesc scan, + TBMIterateResult *tbmres, + TupleTableSlot *slot) +{ + elog(ERROR, "no_storage_scan_bitmap_next_tuple() failed"); + return false; +} + +static bool +no_storage_scan_sample_next_block(TableScanDesc scan, + SampleScanState *scanstate) +{ + elog(ERROR, "no_storage_scan_sample_next_block() failed"); + return false; +} + +static bool +no_storage_scan_sample_next_tuple(TableScanDesc scan, + SampleScanState *scanstate, + TupleTableSlot *slot) +{ + elog(ERROR, "no_storage_scan_sample_next_tuple() failed"); + return false; +} + + +/* ------------------------------------------------------------------------ + * Definition of the no_storage table access method. + * ------------------------------------------------------------------------ + */ + +static const TableAmRoutine no_storage_methods = { + .type = T_TableAmRoutine, + + .slot_callbacks = no_storage_slot_callbacks, + + .scan_begin = no_storage_scan_begin, + .scan_end = no_storage_scan_end, + .scan_rescan = no_storage_scan_rescan, + .scan_getnextslot = no_storage_scan_getnextslot, + + /* these are common helper functions */ + .parallelscan_estimate = table_block_parallelscan_estimate, + .parallelscan_initialize = table_block_parallelscan_initialize, + .parallelscan_reinitialize = table_block_parallelscan_reinitialize, + + .index_fetch_begin = no_storage_index_fetch_begin, + .index_fetch_reset = no_storage_index_fetch_reset, + .index_fetch_end = no_storage_index_fetch_end, + .index_fetch_tuple = no_storage_index_fetch_tuple, + + .tuple_insert = no_storage_tuple_insert, + .tuple_insert_speculative = no_storage_tuple_insert_speculative, + .tuple_complete_speculative = no_storage_tuple_complete_speculative, + .multi_insert = no_storage_multi_insert, + .tuple_delete = no_storage_tuple_delete, + .tuple_update = no_storage_tuple_update, + .tuple_lock = no_storage_tuple_lock, + .finish_bulk_insert = no_storage_finish_bulk_insert, + + .tuple_fetch_row_version = no_storage_fetch_row_version, + .tuple_get_latest_tid = no_storage_get_latest_tid, + .tuple_tid_valid = no_storage_tuple_tid_valid, + .tuple_satisfies_snapshot = no_storage_tuple_satisfies_snapshot, + .index_delete_tuples = no_storage_index_delete_tuples, + + .relation_set_new_filenode = no_storage_relation_set_new_filenode, + .relation_nontransactional_truncate = no_storage_relation_nontransactional_truncate, + .relation_copy_data = no_storage_copy_data, + .relation_copy_for_cluster = no_storage_copy_for_cluster, + .relation_vacuum = no_storage_vacuum, + .scan_analyze_next_block = no_storage_scan_analyze_next_block, + .scan_analyze_next_tuple = no_storage_scan_analyze_next_tuple, + .index_build_range_scan = no_storage_index_build_range_scan, + .index_validate_scan = no_storage_index_validate_scan, + + .relation_size = no_storage_relation_size, + .relation_needs_toast_table = no_storage_relation_needs_toast_table, + + .relation_estimate_size = no_storage_estimate_rel_size, + + .scan_bitmap_next_block = no_storage_scan_bitmap_next_block, + .scan_bitmap_next_tuple = no_storage_scan_bitmap_next_tuple, + .scan_sample_next_block = no_storage_scan_sample_next_block, + .scan_sample_next_tuple = no_storage_scan_sample_next_tuple +}; + +Datum +no_storage_tableam_handler(PG_FUNCTION_ARGS) +{ + PG_RETURN_POINTER(&no_storage_methods); +} diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c index 5ea5bdd810..5e2660b0e6 100644 --- a/src/backend/access/table/tableam.c +++ b/src/backend/access/table/tableam.c @@ -54,39 +54,6 @@ bool synchronize_seqscans = true; * ---------------------------------------------------------------------------- */ -const TupleTableSlotOps * -table_slot_callbacks(Relation relation) -{ - const TupleTableSlotOps *tts_cb; - - if (relation->rd_tableam) - tts_cb = relation->rd_tableam->slot_callbacks(relation); - else if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE) - { - /* - * Historically FDWs expect to store heap tuples in slots. Continue - * handing them one, to make it less painful to adapt FDWs to new - * versions. The cost of a heap slot over a virtual slot is pretty - * small. - */ - tts_cb = &TTSOpsHeapTuple; - } - else - { - /* - * These need to be supported, as some parts of the code (like COPY) - * need to create slots for such relations too. It seems better to - * centralize the knowledge that a heap slot is the right thing in - * that case here. - */ - Assert(relation->rd_rel->relkind == RELKIND_VIEW || - relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE); - tts_cb = &TTSOpsVirtual; - } - - return tts_cb; -} - TupleTableSlot * table_slot_create(Relation relation, List **reglist) { diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 7ef510cd01..095362b489 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1214,6 +1214,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) case RELKIND_FOREIGN_TABLE: case RELKIND_PARTITIONED_TABLE: Assert(relation->rd_rel->relam == InvalidOid); + RelationInitTableAccessMethod(relation); break; } @@ -1767,7 +1768,23 @@ RelationInitTableAccessMethod(Relation relation) HeapTuple tuple; Form_pg_am aform; - if (relation->rd_rel->relkind == RELKIND_SEQUENCE) + /* nothing to do for indexes */ + if (relation->rd_rel->relkind == RELKIND_INDEX || + relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) + return; + + if (relation->rd_rel->relkind == RELKIND_VIEW || + relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE || + relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE || + relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE) + { + /* + * Relations without storage fall back to their specific to avoid a + * NULL rd_amhandler. + */ + relation->rd_amhandler = F_NO_STORAGE_TABLEAM_HANDLER; + } + else if (relation->rd_rel->relkind == RELKIND_SEQUENCE) { /* * Sequences are currently accessed like heap tables, but it doesn't @@ -3542,11 +3559,7 @@ RelationBuildLocalRelation(const char *relname, rel->rd_rel->relam = accessmtd; - if (relkind == RELKIND_RELATION || - relkind == RELKIND_SEQUENCE || - relkind == RELKIND_TOASTVALUE || - relkind == RELKIND_MATVIEW) - RelationInitTableAccessMethod(rel); + RelationInitTableAccessMethod(rel); /* * Okay to insert into the relcache hash table. @@ -4106,10 +4119,8 @@ RelationCacheInitializePhase3(void) /* Reload tableam data if needed */ if (relation->rd_tableam == NULL && - (relation->rd_rel->relkind == RELKIND_RELATION || - relation->rd_rel->relkind == RELKIND_SEQUENCE || - relation->rd_rel->relkind == RELKIND_TOASTVALUE || - relation->rd_rel->relkind == RELKIND_MATVIEW)) + relation->rd_rel->relkind != RELKIND_INDEX && + relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX) { RelationInitTableAccessMethod(relation); Assert(relation->rd_tableam != NULL); @@ -5883,11 +5894,7 @@ load_relcache_init_file(bool shared) nailed_rels++; /* Load table AM data */ - if (rel->rd_rel->relkind == RELKIND_RELATION || - rel->rd_rel->relkind == RELKIND_SEQUENCE || - rel->rd_rel->relkind == RELKIND_TOASTVALUE || - rel->rd_rel->relkind == RELKIND_MATVIEW) - RelationInitTableAccessMethod(rel); + RelationInitTableAccessMethod(rel); Assert(rel->rd_index == NULL); Assert(rel->rd_indextuple == NULL); diff --git a/src/test/regress/expected/create_am.out b/src/test/regress/expected/create_am.out index 0dfb26c301..c57057e2f6 100644 --- a/src/test/regress/expected/create_am.out +++ b/src/test/regress/expected/create_am.out @@ -129,11 +129,12 @@ ERROR: function int4in(internal) does not exist CREATE ACCESS METHOD bogus TYPE TABLE HANDLER bthandler; ERROR: function bthandler must return type table_am_handler SELECT amname, amhandler, amtype FROM pg_am where amtype = 't' ORDER BY 1, 2; - amname | amhandler | amtype ---------+----------------------+-------- - heap | heap_tableam_handler | t - heap2 | heap_tableam_handler | t -(2 rows) + amname | amhandler | amtype +------------+----------------------------+-------- + heap | heap_tableam_handler | t + heap2 | heap_tableam_handler | t + no_storage | no_storage_tableam_handler | t +(3 rows) -- First create tables employing the new AM using USING -- plain CREATE TABLE diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out index 7204fdb0b4..606b1662d4 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -4898,31 +4898,33 @@ Indexes: -- check printing info about access methods \dA List of access methods - Name | Type ---------+------- - brin | Index - btree | Index - gin | Index - gist | Index - hash | Index - heap | Table - heap2 | Table - spgist | Index -(8 rows) + Name | Type +------------+------- + brin | Index + btree | Index + gin | Index + gist | Index + hash | Index + heap | Table + heap2 | Table + no_storage | Table + spgist | Index +(9 rows) \dA * List of access methods - Name | Type ---------+------- - brin | Index - btree | Index - gin | Index - gist | Index - hash | Index - heap | Table - heap2 | Table - spgist | Index -(8 rows) + Name | Type +------------+------- + brin | Index + btree | Index + gin | Index + gist | Index + hash | Index + heap | Table + heap2 | Table + no_storage | Table + spgist | Index +(9 rows) \dA h* List of access methods @@ -4947,32 +4949,34 @@ List of access methods \dA: extra argument "bar" ignored \dA+ - List of access methods - Name | Type | Handler | Description ---------+-------+----------------------+---------------------------------------- - brin | Index | brinhandler | block range index (BRIN) access method - btree | Index | bthandler | b-tree index access method - gin | Index | ginhandler | GIN index access method - gist | Index | gisthandler | GiST index access method - hash | Index | hashhandler | hash index access method - heap | Table | heap_tableam_handler | heap table access method - heap2 | Table | heap_tableam_handler | - spgist | Index | spghandler | SP-GiST index access method -(8 rows) + List of access methods + Name | Type | Handler | Description +------------+-------+----------------------------+---------------------------------------- + brin | Index | brinhandler | block range index (BRIN) access method + btree | Index | bthandler | b-tree index access method + gin | Index | ginhandler | GIN index access method + gist | Index | gisthandler | GiST index access method + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | + no_storage | Table | no_storage_tableam_handler | no_storage table access method + spgist | Index | spghandler | SP-GiST index access method +(9 rows) \dA+ * - List of access methods - Name | Type | Handler | Description ---------+-------+----------------------+---------------------------------------- - brin | Index | brinhandler | block range index (BRIN) access method - btree | Index | bthandler | b-tree index access method - gin | Index | ginhandler | GIN index access method - gist | Index | gisthandler | GiST index access method - hash | Index | hashhandler | hash index access method - heap | Table | heap_tableam_handler | heap table access method - heap2 | Table | heap_tableam_handler | - spgist | Index | spghandler | SP-GiST index access method -(8 rows) + List of access methods + Name | Type | Handler | Description +------------+-------+----------------------------+---------------------------------------- + brin | Index | brinhandler | block range index (BRIN) access method + btree | Index | bthandler | b-tree index access method + gin | Index | ginhandler | GIN index access method + gist | Index | gisthandler | GiST index access method + hash | Index | hashhandler | hash index access method + heap | Table | heap_tableam_handler | heap table access method + heap2 | Table | heap_tableam_handler | + no_storage | Table | no_storage_tableam_handler | no_storage table access method + spgist | Index | spghandler | SP-GiST index access method +(9 rows) \dA+ h* List of access methods -- 2.30.0
signature.asc
Description: PGP signature