v17-0003-Sequence-access-methods-backend-support.patch
text/x-diff
Filename: v17-0003-Sequence-access-methods-backend-support.patch
Type: text/x-diff
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v17-0003
Subject: Sequence access methods - backend support
| File | + | − |
|---|---|---|
| src/backend/access/sequence/Makefile | 1 | 1 |
| src/backend/access/sequence/meson.build | 1 | 0 |
| src/backend/access/sequence/seqlocalam.c | 32 | 9 |
| src/backend/access/sequence/sequenceamapi.c | 145 | 0 |
| src/backend/access/sequence/sequence.c | 2 | 1 |
| src/backend/catalog/heap.c | 5 | 1 |
| src/backend/commands/amcmds.c | 16 | 0 |
| src/backend/commands/sequence.c | 12 | 11 |
| src/backend/commands/tablecmds.c | 13 | 4 |
| src/backend/nodes/gen_node_support.pl | 2 | 0 |
| src/backend/nodes/Makefile | 1 | 0 |
| src/backend/parser/gram.y | 11 | 1 |
| src/backend/parser/parse_utilcmd.c | 2 | 0 |
| src/backend/utils/adt/pseudotypes.c | 1 | 0 |
| src/backend/utils/cache/relcache.c | 72 | 19 |
| src/backend/utils/misc/guc_tables.c | 12 | 0 |
| src/backend/utils/misc/postgresql.conf.sample | 1 | 0 |
| src/bin/psql/describe.c | 2 | 0 |
| src/bin/psql/tab-complete.in.c | 2 | 2 |
| src/include/access/seqlocalam.h | 0 | 15 |
| src/include/access/sequenceam.h | 181 | 0 |
| src/include/catalog/pg_am.dat | 3 | 0 |
| src/include/catalog/pg_am.h | 1 | 0 |
| src/include/catalog/pg_class.h | 6 | 0 |
| src/include/catalog/pg_proc.dat | 13 | 0 |
| src/include/catalog/pg_type.dat | 6 | 0 |
| src/include/commands/defrem.h | 1 | 0 |
| src/include/commands/sequence.h | 0 | 34 |
| src/include/nodes/meson.build | 1 | 0 |
| src/include/nodes/parsenodes.h | 1 | 0 |
| src/include/utils/guc_hooks.h | 2 | 0 |
| src/include/utils/rel.h | 5 | 0 |
| src/test/regress/expected/create_am.out | 36 | 19 |
| src/test/regress/expected/opr_sanity.out | 12 | 0 |
| src/test/regress/expected/psql.out | 50 | 46 |
| src/test/regress/expected/type_sanity.out | 6 | 6 |
| src/test/regress/sql/create_am.sql | 19 | 5 |
| src/test/regress/sql/opr_sanity.sql | 10 | 0 |
| src/test/regress/sql/type_sanity.sql | 6 | 6 |
| src/tools/pgindent/typedefs.list | 3 | 2 |
From 383387ee0811f8499de10a599fd4927006946e18 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Wed, 4 Dec 2024 08:09:46 +0900
Subject: [PATCH v17 3/6] Sequence access methods - backend support
The "seqlocal" sequence AM is now plugged in as a handler in the
relcache, and a set of callbacks in sequenceam.h.
---
src/include/access/seqlocalam.h | 15 --
src/include/access/sequenceam.h | 181 ++++++++++++++++++
src/include/catalog/pg_am.dat | 3 +
src/include/catalog/pg_am.h | 1 +
src/include/catalog/pg_class.h | 6 +
src/include/catalog/pg_proc.dat | 13 ++
src/include/catalog/pg_type.dat | 6 +
src/include/commands/defrem.h | 1 +
src/include/commands/sequence.h | 34 ----
src/include/nodes/meson.build | 1 +
src/include/nodes/parsenodes.h | 1 +
src/include/utils/guc_hooks.h | 2 +
src/include/utils/rel.h | 5 +
src/backend/access/sequence/Makefile | 2 +-
src/backend/access/sequence/meson.build | 1 +
src/backend/access/sequence/seqlocalam.c | 41 +++-
src/backend/access/sequence/sequence.c | 3 +-
src/backend/access/sequence/sequenceamapi.c | 145 ++++++++++++++
src/backend/catalog/heap.c | 6 +-
src/backend/commands/amcmds.c | 16 ++
src/backend/commands/sequence.c | 23 +--
src/backend/commands/tablecmds.c | 17 +-
src/backend/nodes/Makefile | 1 +
src/backend/nodes/gen_node_support.pl | 2 +
src/backend/parser/gram.y | 12 +-
src/backend/parser/parse_utilcmd.c | 2 +
src/backend/utils/adt/pseudotypes.c | 1 +
src/backend/utils/cache/relcache.c | 91 +++++++--
src/backend/utils/misc/guc_tables.c | 12 ++
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/bin/psql/describe.c | 2 +
src/bin/psql/tab-complete.in.c | 4 +-
src/test/regress/expected/create_am.out | 55 ++++--
src/test/regress/expected/opr_sanity.out | 12 ++
src/test/regress/expected/psql.out | 96 +++++-----
src/test/regress/expected/type_sanity.out | 12 +-
src/test/regress/sql/create_am.sql | 24 ++-
src/test/regress/sql/opr_sanity.sql | 10 +
src/test/regress/sql/type_sanity.sql | 12 +-
src/tools/pgindent/typedefs.list | 5 +-
40 files changed, 695 insertions(+), 182 deletions(-)
create mode 100644 src/include/access/sequenceam.h
create mode 100644 src/backend/access/sequence/sequenceamapi.c
diff --git a/src/include/access/seqlocalam.h b/src/include/access/seqlocalam.h
index 225fb9a2cbeb..21936511ac2b 100644
--- a/src/include/access/seqlocalam.h
+++ b/src/include/access/seqlocalam.h
@@ -15,7 +15,6 @@
#include "access/xlogreader.h"
#include "storage/relfilelocator.h"
-#include "utils/rel.h"
/* XLOG stuff */
#define XLOG_SEQ_LOCAL_LOG 0x00
@@ -41,18 +40,4 @@ extern void seq_local_desc(StringInfo buf, XLogReaderState *record);
extern const char *seq_local_identify(uint8 info);
extern void seq_local_mask(char *page, BlockNumber blkno);
-/* access routines */
-extern int64 seq_local_nextval(Relation rel, int64 incby, int64 maxv,
- int64 minv, int64 cache, bool cycle,
- int64 *last);
-extern const char *seq_local_get_table_am(void);
-extern void seq_local_init(Relation rel, int64 last_value, bool is_called);
-extern void seq_local_setval(Relation rel, int64 next, bool iscalled);
-extern void seq_local_reset(Relation rel, int64 startv, bool is_called,
- bool reset_state);
-extern void seq_local_get_state(Relation rel, int64 *last_value,
- bool *is_called);
-extern void seq_local_change_persistence(Relation rel,
- char newrelpersistence);
-
#endif /* SEQLOCALAM_H */
diff --git a/src/include/access/sequenceam.h b/src/include/access/sequenceam.h
new file mode 100644
index 000000000000..ac48c8b468be
--- /dev/null
+++ b/src/include/access/sequenceam.h
@@ -0,0 +1,181 @@
+/*-------------------------------------------------------------------------
+ *
+ * sequenceam.h
+ * POSTGRES sequence access method definitions.
+ *
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/access/sequenceam.h
+ *
+ * NOTES
+ * See sequenceam.sgml for higher level documentation.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SEQUENCEAM_H
+#define SEQUENCEAM_H
+
+#include "utils/rel.h"
+
+#define DEFAULT_SEQUENCE_ACCESS_METHOD "seqlocal"
+
+/* GUCs */
+extern PGDLLIMPORT char *default_sequence_access_method;
+
+/*
+ * API struct for a sequence AM. Note this must be allocated in a
+ * server-lifetime manner, typically as a static const struct, which then gets
+ * returned by FormData_pg_am.amhandler.
+ *
+ * In most cases it's not appropriate to call the callbacks directly, use the
+ * sequence_* wrapper functions instead.
+ *
+ * GetSequenceAmRoutine() asserts that required callbacks are filled in,
+ * remember to update when adding a callback.
+ */
+typedef struct SequenceAmRoutine
+{
+ /* this must be set to T_SequenceAmRoutine */
+ NodeTag type;
+
+ /*
+ * Retrieve table access method used by a sequence to store its metadata.
+ */
+ const char *(*get_table_am) (void);
+
+ /*
+ * Initialize sequence after creating a sequence Relation in pg_class,
+ * setting up the sequence for use. "last_value" and "is_called" are
+ * guessed from the options set for the sequence in CREATE SEQUENCE, based
+ * on the configuration of pg_sequence.
+ */
+ void (*init) (Relation rel, int64 last_value, bool is_called);
+
+ /*
+ * Retrieve a result for nextval(), based on the options retrieved from
+ * the sequence's options in pg_sequence. "last" is the last value
+ * calculated stored in the session's local cache, for lastval().
+ */
+ int64 (*nextval) (Relation rel, int64 incby, int64 maxv,
+ int64 minv, int64 cache, bool cycle,
+ int64 *last);
+
+ /*
+ * Callback to set the state of a sequence, based on the input arguments
+ * from setval().
+ */
+ void (*setval) (Relation rel, int64 next, bool iscalled);
+
+ /*
+ * Reset a sequence to its initial value. "reset_state", if set to true,
+ * means that the sequence parameters have changed, hence its internal
+ * state may need to be reset as well. "startv" and "is_called" are
+ * values guessed from the configuration of the sequence, based on the
+ * contents of pg_sequence.
+ */
+ void (*reset) (Relation rel, int64 startv, bool is_called,
+ bool reset_state);
+
+ /*
+ * Returns the current state of a sequence, returning data for
+ * pg_sequence_last_value() and related DDLs like ALTER SEQUENCE.
+ * "last_value" and "is_called" should be assigned to the values retrieved
+ * from the sequence Relation.
+ */
+ void (*get_state) (Relation rel, int64 *last_value, bool *is_called);
+
+ /*
+ * Callback used when switching persistence of a sequence Relation, to
+ * reset the sequence based on its new persistence "newrelpersistence".
+ */
+ void (*change_persistence) (Relation rel, char newrelpersistence);
+
+} SequenceAmRoutine;
+
+
+/* ---------------------------------------------------------------------------
+ * Wrapper functions for each callback.
+ * ---------------------------------------------------------------------------
+ */
+
+/*
+ * Returns the name of the table access method used by this sequence.
+ */
+static inline const char *
+sequence_get_table_am(Relation rel)
+{
+ return rel->rd_sequenceam->get_table_am();
+}
+
+/*
+ * Insert tuple data based on the information guessed from the contents
+ * of pg_sequence.
+ */
+static inline void
+sequence_init(Relation rel, int64 last_value, bool is_called)
+{
+ rel->rd_sequenceam->init(rel, last_value, is_called);
+}
+
+/*
+ * Allocate a set of values for the given sequence. "last" is the last value
+ * allocated. The result returned is the next value of the sequence computed.
+ */
+static inline int64
+sequence_nextval(Relation rel, int64 incby, int64 maxv,
+ int64 minv, int64 cache, bool cycle,
+ int64 *last)
+{
+ return rel->rd_sequenceam->nextval(rel, incby, maxv, minv, cache,
+ cycle, last);
+}
+
+/*
+ * Callback to set the state of a sequence, based on the input arguments
+ * from setval().
+ */
+static inline void
+sequence_setval(Relation rel, int64 next, bool iscalled)
+{
+ rel->rd_sequenceam->setval(rel, next, iscalled);
+}
+
+/*
+ * Reset a sequence to its initial state.
+ */
+static inline void
+sequence_reset(Relation rel, int64 startv, bool is_called,
+ bool reset_state)
+{
+ rel->rd_sequenceam->reset(rel, startv, is_called, reset_state);
+}
+
+/*
+ * Retrieve sequence metadata.
+ */
+static inline void
+sequence_get_state(Relation rel, int64 *last_value, bool *is_called)
+{
+ rel->rd_sequenceam->get_state(rel, last_value, is_called);
+}
+
+/*
+ * Callback to change the persistence of a sequence Relation.
+ */
+static inline void
+sequence_change_persistence(Relation rel, char newrelpersistence)
+{
+ rel->rd_sequenceam->change_persistence(rel, newrelpersistence);
+}
+
+/* ----------------------------------------------------------------------------
+ * Functions in sequenceamapi.c
+ * ----------------------------------------------------------------------------
+ */
+
+extern const SequenceAmRoutine *GetSequenceAmRoutine(Oid amhandler);
+extern Oid GetSequenceAmRoutineId(Oid amoid);
+
+#endif /* SEQUENCEAM_H */
diff --git a/src/include/catalog/pg_am.dat b/src/include/catalog/pg_am.dat
index 26d15928a155..8f076fcec958 100644
--- a/src/include/catalog/pg_am.dat
+++ b/src/include/catalog/pg_am.dat
@@ -15,6 +15,9 @@
{ oid => '2', oid_symbol => 'HEAP_TABLE_AM_OID',
descr => 'heap table access method',
amname => 'heap', amhandler => 'heap_tableam_handler', amtype => 't' },
+{ oid => '8051', oid_symbol => 'LOCAL_SEQUENCE_AM_OID',
+ descr => 'local sequence access method',
+ amname => 'seqlocal', amhandler => 'seq_local_sequenceam_handler', amtype => 's' },
{ 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_am.h b/src/include/catalog/pg_am.h
index 6e98a0930c27..080bea5031a9 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -59,6 +59,7 @@ MAKE_SYSCACHE(AMOID, pg_am_oid_index, 4);
* Allowed values for amtype
*/
#define AMTYPE_INDEX 'i' /* index access method */
+#define AMTYPE_SEQUENCE 's' /* sequence access method */
#define AMTYPE_TABLE 't' /* table access method */
#endif /* EXPOSE_TO_CLIENT_CODE */
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 07d182da796a..012a2863c037 100644
--- a/src/include/catalog/pg_class.h
+++ b/src/include/catalog/pg_class.h
@@ -231,6 +231,12 @@ MAKE_SYSCACHE(RELNAMENSP, pg_class_relname_nsp_index, 128);
(relkind) == RELKIND_TOASTVALUE || \
(relkind) == RELKIND_MATVIEW)
+/*
+ * Relation kinds with a sequence access method (rd_sequenceam).
+ */
+#define RELKIND_HAS_SEQUENCE_AM(relkind) \
+ ((relkind) == RELKIND_SEQUENCE)
+
#endif /* EXPOSE_TO_CLIENT_CODE */
extern int errdetail_relkind_not_supported(char relkind);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 118d6da1ace0..b272b4885e6e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -913,6 +913,12 @@
prorettype => 'table_am_handler', proargtypes => 'internal',
prosrc => 'heap_tableam_handler' },
+# Sequence access method handlers
+{ oid => '8209', descr => 'local sequence access method handler',
+ proname => 'seq_local_sequenceam_handler', provolatile => 'v',
+ prorettype => 'sequence_am_handler', proargtypes => 'internal',
+ prosrc => 'seq_local_sequenceam_handler' },
+
# Index access method handlers
{ oid => '330', descr => 'btree index access method handler',
proname => 'bthandler', provolatile => 'v', prorettype => 'index_am_handler',
@@ -7894,6 +7900,13 @@
{ oid => '327', descr => 'I/O',
proname => 'index_am_handler_out', prorettype => 'cstring',
proargtypes => 'index_am_handler', prosrc => 'index_am_handler_out' },
+{ oid => '8207', descr => 'I/O',
+ proname => 'sequence_am_handler_in', proisstrict => 'f',
+ prorettype => 'sequence_am_handler', proargtypes => 'cstring',
+ prosrc => 'sequence_am_handler_in' },
+{ oid => '8208', descr => 'I/O',
+ proname => 'sequence_am_handler_out', prorettype => 'cstring',
+ proargtypes => 'sequence_am_handler', prosrc => 'sequence_am_handler_out' },
{ oid => '3311', descr => 'I/O',
proname => 'tsm_handler_in', proisstrict => 'f', prorettype => 'tsm_handler',
proargtypes => 'cstring', prosrc => 'tsm_handler_in' },
diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat
index cb730aeac864..d0054c5c988c 100644
--- a/src/include/catalog/pg_type.dat
+++ b/src/include/catalog/pg_type.dat
@@ -632,6 +632,12 @@
typcategory => 'P', typinput => 'index_am_handler_in',
typoutput => 'index_am_handler_out', typreceive => '-', typsend => '-',
typalign => 'i' },
+{ oid => '8210',
+ descr => 'pseudo-type for the result of a sequence AM handler function',
+ typname => 'sequence_am_handler', typlen => '4', typbyval => 't',
+ typtype => 'p', typcategory => 'P', typinput => 'sequence_am_handler_in',
+ typoutput => 'sequence_am_handler_out', typreceive => '-', typsend => '-',
+ typalign => 'i' },
{ oid => '3310',
descr => 'pseudo-type for the result of a tablesample method function',
typname => 'tsm_handler', typlen => '4', typbyval => 't', typtype => 'p',
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index dd22b5efdfd9..6790728aced3 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -145,6 +145,7 @@ extern Datum transformGenericOptions(Oid catalogId,
extern ObjectAddress CreateAccessMethod(CreateAmStmt *stmt);
extern Oid get_index_am_oid(const char *amname, bool missing_ok);
extern Oid get_table_am_oid(const char *amname, bool missing_ok);
+extern Oid get_sequence_am_oid(const char *amname, bool missing_ok);
extern Oid get_am_oid(const char *amname, bool missing_ok);
extern char *get_am_name(Oid amOid);
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 9ac0b67683d3..7693e9941fc9 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -22,35 +22,6 @@
#include "storage/relfilelocator.h"
-typedef struct FormData_pg_sequence_data
-{
- int64 last_value;
- int64 log_cnt;
- bool is_called;
-} FormData_pg_sequence_data;
-
-typedef FormData_pg_sequence_data *Form_pg_sequence_data;
-
-/*
- * Columns of a sequence relation
- */
-
-#define SEQ_COL_LASTVAL 1
-#define SEQ_COL_LOG 2
-#define SEQ_COL_CALLED 3
-
-#define SEQ_COL_FIRSTCOL SEQ_COL_LASTVAL
-#define SEQ_COL_LASTCOL SEQ_COL_CALLED
-
-/* XLOG stuff */
-#define XLOG_SEQ_LOG 0x00
-
-typedef struct xl_seq_rec
-{
- RelFileLocator locator;
- /* SEQUENCE TUPLE DATA FOLLOWS AT THE END */
-} xl_seq_rec;
-
extern int64 nextval_internal(Oid relid, bool check_permissions);
extern Datum nextval(PG_FUNCTION_ARGS);
extern List *sequence_options(Oid relid);
@@ -62,9 +33,4 @@ extern void DeleteSequenceTuple(Oid relid);
extern void ResetSequence(Oid seq_relid);
extern void ResetSequenceCaches(void);
-extern void seq_redo(XLogReaderState *record);
-extern void seq_desc(StringInfo buf, XLogReaderState *record);
-extern const char *seq_identify(uint8 info);
-extern void seq_mask(char *page, BlockNumber blkno);
-
#endif /* SEQUENCE_H */
diff --git a/src/include/nodes/meson.build b/src/include/nodes/meson.build
index ea36cb0fda40..c0311fbe8220 100644
--- a/src/include/nodes/meson.build
+++ b/src/include/nodes/meson.build
@@ -10,6 +10,7 @@ node_support_input_i = [
'access/amapi.h',
'access/cmptype.h',
'access/sdir.h',
+ 'access/sequenceam.h',
'access/tableam.h',
'access/tsmapi.h',
'commands/event_trigger.h',
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 58ee44e2b617..9d2bd341d104 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3224,6 +3224,7 @@ typedef struct CreateSeqStmt
List *options;
Oid ownerId; /* ID of owner, or InvalidOid for default */
bool for_identity;
+ char *accessMethod; /* USING name of access method (eg. local) */
bool if_not_exists; /* just do nothing if it already exists? */
} CreateSeqStmt;
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index 82ac8646a8d4..ab5e2eab0401 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -55,6 +55,8 @@ extern bool check_log_connections(char **newval, void **extra, GucSource source)
extern void assign_log_connections(const char *newval, void *extra);
extern bool check_default_table_access_method(char **newval, void **extra,
GucSource source);
+extern bool check_default_sequence_access_method(char **newval, void **extra,
+ GucSource source);
extern bool check_default_tablespace(char **newval, void **extra,
GucSource source);
extern bool check_default_text_search_config(char **newval, void **extra, GucSource source);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index b552359915f1..4e418968253d 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -188,6 +188,11 @@ typedef struct RelationData
*/
const struct TableAmRoutine *rd_tableam;
+ /*
+ * Sequence access method.
+ */
+ const struct SequenceAmRoutine *rd_sequenceam;
+
/* These are non-NULL only for an index relation: */
Form_pg_index rd_index; /* pg_index tuple describing this index */
/* use "struct" here to avoid needing to include htup.h: */
diff --git a/src/backend/access/sequence/Makefile b/src/backend/access/sequence/Makefile
index a15ceec1c0a0..62006165a15f 100644
--- a/src/backend/access/sequence/Makefile
+++ b/src/backend/access/sequence/Makefile
@@ -12,6 +12,6 @@ subdir = src/backend/access/sequence
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = seqlocalam.o seqlocalxlog.o sequence.o
+OBJS = seqlocalam.o seqlocalxlog.o sequence.o sequenceamapi.o
include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/sequence/meson.build b/src/backend/access/sequence/meson.build
index 8bc0e95e68c0..d82af34d538c 100644
--- a/src/backend/access/sequence/meson.build
+++ b/src/backend/access/sequence/meson.build
@@ -4,4 +4,5 @@ backend_sources += files(
'seqlocalam.c',
'seqlocalxlog.c',
'sequence.c',
+ 'sequenceamapi.c',
)
diff --git a/src/backend/access/sequence/seqlocalam.c b/src/backend/access/sequence/seqlocalam.c
index e019a6f5a95d..5dec9d51ec82 100644
--- a/src/backend/access/sequence/seqlocalam.c
+++ b/src/backend/access/sequence/seqlocalam.c
@@ -17,6 +17,7 @@
#include "access/multixact.h"
#include "access/seqlocalam.h"
+#include "access/sequenceam.h"
#include "access/xact.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
@@ -24,6 +25,7 @@
#include "commands/tablecmds.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
+#include "utils/builtins.h"
/*
@@ -230,10 +232,10 @@ fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
* Allocate a new value for a local sequence, based on the sequence
* configuration.
*/
-int64
+static int64
seq_local_nextval(Relation rel, int64 incby, int64 maxv,
- int64 minv, int64 cache, bool cycle,
- int64 *last)
+ int64 minv, int64 cache, bool cycle,
+ int64 *last)
{
int64 result;
int64 fetch;
@@ -417,7 +419,7 @@ seq_local_nextval(Relation rel, int64 incby, int64 maxv,
*
* Return the table access method used by this sequence.
*/
-const char *
+static const char *
seq_local_get_table_am(void)
{
return "heap";
@@ -432,7 +434,7 @@ seq_local_get_table_am(void)
* inserted after the relation has been created, filling in its heap
* table.
*/
-void
+static void
seq_local_init(Relation rel, int64 last_value, bool is_called)
{
Datum value[SEQ_LOCAL_COL_LASTCOL];
@@ -499,7 +501,7 @@ seq_local_init(Relation rel, int64 last_value, bool is_called)
*
* Callback for setval().
*/
-void
+static void
seq_local_setval(Relation rel, int64 next, bool iscalled)
{
Buffer buf;
@@ -547,7 +549,7 @@ seq_local_setval(Relation rel, int64 next, bool iscalled)
* Perform a hard reset on the local sequence, rewriting its heap data
* entirely.
*/
-void
+static void
seq_local_reset(Relation rel, int64 startv, bool is_called, bool reset_state)
{
Form_pg_seq_local_data seq;
@@ -600,7 +602,7 @@ seq_local_reset(Relation rel, int64 startv, bool is_called, bool reset_state)
*
* Retrieve the state of a local sequence.
*/
-void
+static void
seq_local_get_state(Relation rel, int64 *last_value, bool *is_called)
{
Buffer buf;
@@ -621,7 +623,7 @@ seq_local_get_state(Relation rel, int64 *last_value, bool *is_called)
*
* Persistence change for the local sequence Relation.
*/
-void
+static void
seq_local_change_persistence(Relation rel, char newrelpersistence)
{
Buffer buf;
@@ -632,3 +634,24 @@ seq_local_change_persistence(Relation rel, char newrelpersistence)
fill_seq_with_data(rel, &seqdatatuple);
UnlockReleaseBuffer(buf);
}
+
+/* ------------------------------------------------------------------------
+ * Definition of the local sequence access method.
+ * ------------------------------------------------------------------------
+ */
+static const SequenceAmRoutine seq_local_methods = {
+ .type = T_SequenceAmRoutine,
+ .get_table_am = seq_local_get_table_am,
+ .init = seq_local_init,
+ .nextval = seq_local_nextval,
+ .setval = seq_local_setval,
+ .reset = seq_local_reset,
+ .get_state = seq_local_get_state,
+ .change_persistence = seq_local_change_persistence
+};
+
+Datum
+seq_local_sequenceam_handler(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_POINTER(&seq_local_methods);
+}
diff --git a/src/backend/access/sequence/sequence.c b/src/backend/access/sequence/sequence.c
index 8b5303553702..f30317d1feae 100644
--- a/src/backend/access/sequence/sequence.c
+++ b/src/backend/access/sequence/sequence.c
@@ -13,7 +13,8 @@
*
* NOTES
* This file contains sequence_ routines that implement access to sequences
- * (in contrast to other relation types like indexes).
+ * (in contrast to other relation types like indexes) that are independent
+ * of individual sequence access methods.
*
*-------------------------------------------------------------------------
*/
diff --git a/src/backend/access/sequence/sequenceamapi.c b/src/backend/access/sequence/sequenceamapi.c
new file mode 100644
index 000000000000..dd1a60d827a4
--- /dev/null
+++ b/src/backend/access/sequence/sequenceamapi.c
@@ -0,0 +1,145 @@
+/*-------------------------------------------------------------------------
+ *
+ * sequenceamapi.c
+ * general sequence access method routines
+ *
+ * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/access/sequence/sequenceamapi.c
+ *
+ *
+ * Sequence access method allows the SQL Standard Sequence objects to be
+ * managed according to either the default access method or a pluggable
+ * replacement. Each sequence can only use one access method at a time,
+ * though different sequence access methods can be in use by different
+ * sequences at the same time.
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/xact.h"
+#include "access/sequenceam.h"
+#include "catalog/pg_am.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "utils/guc_hooks.h"
+#include "utils/syscache.h"
+
+
+/* GUC */
+char *default_sequence_access_method = DEFAULT_SEQUENCE_ACCESS_METHOD;
+
+/*
+ * GetSequenceAmRoutine
+ * Call the specified access method handler routine to get its
+ * SequenceAmRoutine struct, which will be palloc'd in the caller's
+ * memory context.
+ */
+const SequenceAmRoutine *
+GetSequenceAmRoutine(Oid amhandler)
+{
+ Datum datum;
+ SequenceAmRoutine *routine;
+
+ datum = OidFunctionCall0(amhandler);
+ routine = (SequenceAmRoutine *) DatumGetPointer(datum);
+
+ if (routine == NULL || !IsA(routine, SequenceAmRoutine))
+ elog(ERROR, "sequence access method handler %u did not return a SequenceAmRoutine struct",
+ amhandler);
+
+ /*
+ * Assert that all required callbacks are present. That makes it a bit
+ * easier to keep AMs up to date, e.g. when forward porting them to a new
+ * major version.
+ */
+ Assert(routine->get_table_am != NULL);
+ Assert(routine->init != NULL);
+ Assert(routine->nextval != NULL);
+ Assert(routine->setval != NULL);
+ Assert(routine->reset != NULL);
+ Assert(routine->get_state != NULL);
+ Assert(routine->change_persistence != NULL);
+
+ return routine;
+}
+
+/*
+ * GetSequenceAmRoutineId
+ * Call pg_am and retrieve the OID of the access method handler.
+ */
+Oid
+GetSequenceAmRoutineId(Oid amoid)
+{
+ Oid amhandleroid;
+ HeapTuple tuple;
+ Form_pg_am aform;
+
+ tuple = SearchSysCache1(AMOID,
+ ObjectIdGetDatum(amoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u", amoid);
+ aform = (Form_pg_am) GETSTRUCT(tuple);
+ Assert(aform->amtype == AMTYPE_SEQUENCE);
+ amhandleroid = aform->amhandler;
+ ReleaseSysCache(tuple);
+
+ return amhandleroid;
+}
+
+/* check_hook: validate new default_sequence_access_method */
+bool
+check_default_sequence_access_method(char **newval, void **extra,
+ GucSource source)
+{
+ if (**newval == '\0')
+ {
+ GUC_check_errdetail("%s cannot be empty.",
+ "default_sequence_access_method");
+ return false;
+ }
+
+ if (strlen(*newval) >= NAMEDATALEN)
+ {
+ GUC_check_errdetail("%s is too long (maximum %d characters).",
+ "default_sequence_access_method", NAMEDATALEN - 1);
+ return false;
+ }
+
+ /*
+ * If we aren't inside a transaction, or not connected to a database, we
+ * cannot do the catalog access necessary to verify the method. Must
+ * accept the value on faith.
+ */
+ if (IsTransactionState() && MyDatabaseId != InvalidOid)
+ {
+ if (!OidIsValid(get_sequence_am_oid(*newval, true)))
+ {
+ /*
+ * When source == PGC_S_TEST, don't throw a hard error for a
+ * nonexistent sequence access method, only a NOTICE. See comments
+ * in guc.h.
+ */
+ if (source == PGC_S_TEST)
+ {
+ ereport(NOTICE,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("sequence access method \"%s\" does not exist",
+ *newval)));
+ }
+ else
+ {
+ GUC_check_errdetail("sequence access method \"%s\" does not exist.",
+ *newval);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index fd6537567ea2..e774dfa86e4e 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1490,9 +1490,13 @@ heap_create_with_catalog(const char *relname,
* No need to add an explicit dependency for the toast table, as the
* main table depends on it. Partitioned tables may not have an
* access method set.
+ *
+ * Sequences and tables are created with their access method ID
+ * given by the caller of this function.
*/
if ((RELKIND_HAS_TABLE_AM(relkind) && relkind != RELKIND_TOASTVALUE) ||
- (relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)))
+ (relkind == RELKIND_PARTITIONED_TABLE && OidIsValid(accessmtd)) ||
+ RELKIND_HAS_SEQUENCE_AM(relkind))
{
ObjectAddressSet(referenced, AccessMethodRelationId, accessmtd);
add_exact_object_address(&referenced, addrs);
diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c
index 58ed9d216cc0..e44633d13b60 100644
--- a/src/backend/commands/amcmds.c
+++ b/src/backend/commands/amcmds.c
@@ -15,6 +15,7 @@
#include "access/htup_details.h"
#include "access/table.h"
+#include "access/sequenceam.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
@@ -175,6 +176,16 @@ get_table_am_oid(const char *amname, bool missing_ok)
return get_am_type_oid(amname, AMTYPE_TABLE, missing_ok);
}
+/*
+ * get_sequence_am_oid - given an access method name, look up its OID
+ * and verify it corresponds to an sequence AM.
+ */
+Oid
+get_sequence_am_oid(const char *amname, bool missing_ok)
+{
+ return get_am_type_oid(amname, AMTYPE_SEQUENCE, missing_ok);
+}
+
/*
* get_am_oid - given an access method name, look up its OID.
* The type is not checked.
@@ -215,6 +226,8 @@ get_am_type_string(char amtype)
{
case AMTYPE_INDEX:
return "INDEX";
+ case AMTYPE_SEQUENCE:
+ return "SEQUENCE";
case AMTYPE_TABLE:
return "TABLE";
default:
@@ -251,6 +264,9 @@ lookup_am_handler_func(List *handler_name, char amtype)
case AMTYPE_INDEX:
expectedType = INDEX_AM_HANDLEROID;
break;
+ case AMTYPE_SEQUENCE:
+ expectedType = SEQUENCE_AM_HANDLEROID;
+ break;
case AMTYPE_TABLE:
expectedType = TABLE_AM_HANDLEROID;
break;
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 41cfa4f1b9a5..e2ebede15116 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -16,10 +16,10 @@
#include "access/bufmask.h"
#include "access/htup_details.h"
-#include "access/seqlocalam.h"
#include "access/multixact.h"
#include "access/relation.h"
#include "access/sequence.h"
+#include "access/sequenceam.h"
#include "access/table.h"
#include "access/transam.h"
#include "access/xact.h"
@@ -152,6 +152,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
stmt->inhRelations = NIL;
stmt->constraints = NIL;
stmt->options = NIL;
+ stmt->accessMethod = seq->accessMethod ? pstrdup(seq->accessMethod) : NULL;
stmt->oncommit = ONCOMMIT_NOOP;
stmt->tablespacename = NULL;
stmt->if_not_exists = seq->if_not_exists;
@@ -173,7 +174,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
rel = sequence_open(seqoid, AccessExclusiveLock);
/* now initialize the sequence table structure and its data */
- seq_local_init(rel, last_value, is_called);
+ sequence_init(rel, last_value, is_called);
/* process OWNED BY if given */
if (owned_by)
@@ -241,7 +242,7 @@ ResetSequence(Oid seq_relid)
ReleaseSysCache(pgstuple);
/* Sequence state is forcibly reset here. */
- seq_local_reset(seq_rel, startv, false, true);
+ sequence_reset(seq_rel, startv, false, true);
/* Clear local cache so that we don't think we have cached numbers */
/* Note that we do not change the currval() state */
@@ -297,7 +298,7 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
seqform = (Form_pg_sequence) GETSTRUCT(seqtuple);
/* Read sequence data */
- seq_local_get_state(seqrel, &last_value, &is_called);
+ sequence_get_state(seqrel, &last_value, &is_called);
/* Check and set new values */
init_params(pstate, stmt->options, stmt->for_identity, false,
@@ -310,7 +311,7 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt)
if (RelationNeedsWAL(seqrel))
GetTopTransactionId();
- seq_local_reset(seqrel, last_value, is_called, reset_state);
+ sequence_reset(seqrel, last_value, is_called, reset_state);
}
/* Clear local cache so that we don't think we have cached numbers */
@@ -353,7 +354,7 @@ SequenceChangePersistence(Oid relid, char newrelpersistence)
if (RelationNeedsWAL(seqrel))
GetTopTransactionId();
- seq_local_change_persistence(seqrel, newrelpersistence);
+ sequence_change_persistence(seqrel, newrelpersistence);
sequence_close(seqrel, NoLock);
}
@@ -470,8 +471,8 @@ nextval_internal(Oid relid, bool check_permissions)
ReleaseSysCache(pgstuple);
/* retrieve next value from the access method */
- result = seq_local_nextval(seqrel, incby, maxv, minv, cache, cycle,
- &last);
+ result = sequence_nextval(seqrel, incby, maxv, minv, cache, cycle,
+ &last);
/* save info in local cache */
elm->increment = incby;
@@ -625,7 +626,7 @@ do_setval(Oid relid, int64 next, bool iscalled)
GetTopTransactionId();
/* Call the access method callback */
- seq_local_setval(seqrel, next, iscalled);
+ sequence_setval(seqrel, next, iscalled);
sequence_close(seqrel, NoLock);
}
@@ -1353,7 +1354,7 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
bool is_called;
int64 last_value;
- seq_local_get_state(seqrel, &last_value, &is_called);
+ sequence_get_state(seqrel, &last_value, &is_called);
values[0] = Int64GetDatum(last_value);
values[1] = BoolGetDatum(is_called);
@@ -1400,7 +1401,7 @@ pg_sequence_last_value(PG_FUNCTION_ARGS)
!RELATION_IS_OTHER_TEMP(seqrel) &&
(RelationIsPermanent(seqrel) || !RecoveryInProgress()))
{
- seq_local_get_state(seqrel, &result, &is_called);
+ sequence_get_state(seqrel, &result, &is_called);
}
sequence_close(seqrel, NoLock);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b1cbb14c3d08..c61dd48f2a18 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -23,6 +23,7 @@
#include "access/reloptions.h"
#include "access/relscan.h"
#include "access/sysattr.h"
+#include "access/sequenceam.h"
#include "access/tableam.h"
#include "access/toast_compression.h"
#include "access/xact.h"
@@ -1025,14 +1026,18 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
}
/*
- * For relations with table AM and partitioned tables, select access
- * method to use: an explicitly indicated one, or (in the case of a
+ * For relations with table AM, partitioned tables or sequences, select
+ * access method to use: an explicitly indicated one, or (in the case of a
* partitioned table) the parent's, if it has one.
*/
if (stmt->accessMethod != NULL)
{
- Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE);
- accessMethodId = get_table_am_oid(stmt->accessMethod, false);
+ Assert(RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE ||
+ RELKIND_HAS_SEQUENCE_AM(relkind));
+ if (RELKIND_HAS_SEQUENCE_AM(relkind))
+ accessMethodId = get_sequence_am_oid(stmt->accessMethod, false);
+ else
+ accessMethodId = get_table_am_oid(stmt->accessMethod, false);
}
else if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1045,6 +1050,10 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
if (RELKIND_HAS_TABLE_AM(relkind) && !OidIsValid(accessMethodId))
accessMethodId = get_table_am_oid(default_table_access_method, false);
}
+ else if (RELKIND_HAS_SEQUENCE_AM(relkind))
+ {
+ accessMethodId = get_sequence_am_oid(default_sequence_access_method, false);
+ }
/*
* Create the relation. Inherited defaults and CHECK constraints are
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index 77ddb9ca53f1..64d4dccc936f 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -48,6 +48,7 @@ node_headers = \
access/amapi.h \
access/cmptype.h \
access/sdir.h \
+ access/sequenceam.h \
access/tableam.h \
access/tsmapi.h \
commands/event_trigger.h \
diff --git a/src/backend/nodes/gen_node_support.pl b/src/backend/nodes/gen_node_support.pl
index 9ecddb142314..0c79454f641e 100644
--- a/src/backend/nodes/gen_node_support.pl
+++ b/src/backend/nodes/gen_node_support.pl
@@ -60,6 +60,7 @@ my @all_input_files = qw(
access/amapi.h
access/cmptype.h
access/sdir.h
+ access/sequenceam.h
access/tableam.h
access/tsmapi.h
commands/event_trigger.h
@@ -84,6 +85,7 @@ my @nodetag_only_files = qw(
nodes/execnodes.h
access/amapi.h
access/sdir.h
+ access/sequenceam.h
access/tableam.h
access/tsmapi.h
commands/event_trigger.h
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index db43034b9db5..21188cef3ad8 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -381,6 +381,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> copy_file_name
access_method_clause attr_name
table_access_method_clause name cursor_name file_name
+ sequence_access_method_clause
cluster_index_specification
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
@@ -4981,23 +4982,26 @@ RefreshMatViewStmt:
CreateSeqStmt:
CREATE OptTemp SEQUENCE qualified_name OptSeqOptList
+ sequence_access_method_clause
{
CreateSeqStmt *n = makeNode(CreateSeqStmt);
-
$4->relpersistence = $2;
n->sequence = $4;
n->options = $5;
+ n->accessMethod = $6;
n->ownerId = InvalidOid;
n->if_not_exists = false;
$$ = (Node *) n;
}
| CREATE OptTemp SEQUENCE IF_P NOT EXISTS qualified_name OptSeqOptList
+ sequence_access_method_clause
{
CreateSeqStmt *n = makeNode(CreateSeqStmt);
$7->relpersistence = $2;
n->sequence = $7;
n->options = $8;
+ n->accessMethod = $9;
n->ownerId = InvalidOid;
n->if_not_exists = true;
$$ = (Node *) n;
@@ -5034,6 +5038,11 @@ OptParenthesizedSeqOptList: '(' SeqOptList ')' { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
+sequence_access_method_clause:
+ USING name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
SeqOptList: SeqOptElem { $$ = list_make1($1); }
| SeqOptList SeqOptElem { $$ = lappend($1, $2); }
;
@@ -6037,6 +6046,7 @@ CreateAmStmt: CREATE ACCESS METHOD name TYPE_P am_type HANDLER handler_name
am_type:
INDEX { $$ = AMTYPE_INDEX; }
+ | SEQUENCE { $$ = AMTYPE_SEQUENCE; }
| TABLE { $$ = AMTYPE_TABLE; }
;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index afcf54169c3b..a8fb08752f91 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -26,6 +26,7 @@
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/reloptions.h"
+#include "access/sequenceam.h"
#include "access/table.h"
#include "access/toast_compression.h"
#include "catalog/dependency.h"
@@ -518,6 +519,7 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
seqstmt->sequence->relpersistence = seqpersistence;
seqstmt->options = seqoptions;
+ seqstmt->accessMethod = NULL;
/*
* If a sequence data type was specified, add it to the options. Prepend
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index 317a1f2b282f..68f160dda7d3 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -369,6 +369,7 @@ PSEUDOTYPE_DUMMY_IO_FUNCS(language_handler);
PSEUDOTYPE_DUMMY_IO_FUNCS(fdw_handler);
PSEUDOTYPE_DUMMY_IO_FUNCS(table_am_handler);
PSEUDOTYPE_DUMMY_IO_FUNCS(index_am_handler);
+PSEUDOTYPE_DUMMY_IO_FUNCS(sequence_am_handler);
PSEUDOTYPE_DUMMY_IO_FUNCS(tsm_handler);
PSEUDOTYPE_DUMMY_IO_FUNCS(internal);
PSEUDOTYPE_DUMMY_IO_FUNCS(anyelement);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 6fe268a8eec1..f3fd8d26b185 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -34,6 +34,7 @@
#include "access/multixact.h"
#include "access/parallel.h"
#include "access/reloptions.h"
+#include "access/sequenceam.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
@@ -64,6 +65,7 @@
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
#include "catalog/storage.h"
+#include "commands/defrem.h"
#include "commands/policy.h"
#include "commands/publicationcmds.h"
#include "commands/trigger.h"
@@ -302,6 +304,7 @@ static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
static void RelationBuildTupleDesc(Relation relation);
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt);
static void RelationInitPhysicalAddr(Relation relation);
+static void RelationInitSequenceAccessMethod(Relation relation);
static void load_critical_index(Oid indexoid, Oid heapoid);
static TupleDesc GetPgClassDescriptor(void);
static TupleDesc GetPgIndexDescriptor(void);
@@ -1225,8 +1228,7 @@ retry:
if (relation->rd_rel->relkind == RELKIND_INDEX ||
relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
RelationInitIndexAccessInfo(relation);
- else if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) ||
- relation->rd_rel->relkind == RELKIND_SEQUENCE)
+ else if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
RelationInitTableAccessMethod(relation);
else if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
@@ -1235,6 +1237,8 @@ retry:
* inherit.
*/
}
+ else if (RELKIND_HAS_SEQUENCE_AM(relation->rd_rel->relkind))
+ RelationInitSequenceAccessMethod(relation);
else
Assert(relation->rd_rel->relam == InvalidOid);
@@ -1831,17 +1835,9 @@ RelationInitTableAccessMethod(Relation relation)
HeapTuple tuple;
Form_pg_am aform;
- if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
- {
- /*
- * Sequences are currently accessed like heap tables, but it doesn't
- * seem prudent to show that in the catalog. So just overwrite it
- * here.
- */
- Assert(relation->rd_rel->relam == InvalidOid);
- relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
- }
- else if (IsCatalogRelation(relation))
+ Assert(RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind));
+
+ if (IsCatalogRelation(relation))
{
/*
* Avoid doing a syscache lookup for catalog tables.
@@ -1872,6 +1868,49 @@ RelationInitTableAccessMethod(Relation relation)
InitTableAmRoutine(relation);
}
+/*
+ * Initialize sequence-access-method support data for a sequence relation
+ */
+static void
+RelationInitSequenceAccessMethod(Relation relation)
+{
+ HeapTuple tuple;
+ Form_pg_am aform;
+ const char *tableam_name;
+ Oid tableam_oid;
+ Oid tableam_handler;
+
+ Assert(RELKIND_HAS_SEQUENCE_AM(relation->rd_rel->relkind));
+
+ /*
+ * Look up the sequence access method, save the OID of its handler
+ * function.
+ */
+ Assert(relation->rd_rel->relam != InvalidOid);
+ relation->rd_amhandler = GetSequenceAmRoutineId(relation->rd_rel->relam);
+
+ /*
+ * Now we can fetch the sequence AM's API struct.
+ */
+ relation->rd_sequenceam = GetSequenceAmRoutine(relation->rd_amhandler);
+
+ /*
+ * From the sequence AM, set its expected table access method.
+ */
+ tableam_name = sequence_get_table_am(relation);
+ tableam_oid = get_table_am_oid(tableam_name, false);
+
+ tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(tableam_oid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for access method %u",
+ tableam_oid);
+ aform = (Form_pg_am) GETSTRUCT(tuple);
+ tableam_handler = aform->amhandler;
+ ReleaseSysCache(tuple);
+
+ relation->rd_tableam = GetTableAmRoutine(tableam_handler);
+}
+
/*
* formrdesc
*
@@ -3711,14 +3750,17 @@ RelationBuildLocalRelation(const char *relname,
rel->rd_rel->relam = accessmtd;
/*
- * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
- * run it in CacheMemoryContext. Fortunately, the remaining steps don't
- * require a long-lived current context.
+ * RelationInitTableAccessMethod() and RelationInitSequenceAccessMethod()
+ * will do syscache lookups, so we mustn't run them in CacheMemoryContext.
+ * Fortunately, the remaining steps don't require a long-lived current
+ * context.
*/
MemoryContextSwitchTo(oldcxt);
- if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
+ if (RELKIND_HAS_TABLE_AM(relkind))
RelationInitTableAccessMethod(rel);
+ else if (relkind == RELKIND_SEQUENCE)
+ RelationInitSequenceAccessMethod(rel);
/*
* Leave index access method uninitialized, because the pg_index row has
@@ -4343,13 +4385,21 @@ RelationCacheInitializePhase3(void)
/* Reload tableam data if needed */
if (relation->rd_tableam == NULL &&
- (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
+ (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind)))
{
RelationInitTableAccessMethod(relation);
Assert(relation->rd_tableam != NULL);
restart = true;
}
+ else if (relation->rd_sequenceam == NULL &&
+ relation->rd_rel->relkind == RELKIND_SEQUENCE)
+ {
+ RelationInitSequenceAccessMethod(relation);
+ Assert(relation->rd_sequenceam != NULL);
+
+ restart = true;
+ }
/* Release hold on the relation */
RelationDecrementReferenceCount(relation);
@@ -6425,8 +6475,10 @@ load_relcache_init_file(bool shared)
nailed_rels++;
/* Load table AM data */
- if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
RelationInitTableAccessMethod(rel);
+ else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ RelationInitSequenceAccessMethod(rel);
Assert(rel->rd_index == NULL);
Assert(rel->rd_indextuple == NULL);
@@ -6438,6 +6490,7 @@ load_relcache_init_file(bool shared)
Assert(rel->rd_supportinfo == NULL);
Assert(rel->rd_indoption == NULL);
Assert(rel->rd_indcollation == NULL);
+ Assert(rel->rd_sequenceam == NULL);
Assert(rel->rd_opcoptions == NULL);
}
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index d14b1678e7fe..f225c85aa196 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -33,6 +33,7 @@
#include "access/gin.h"
#include "access/slru.h"
#include "access/toast_compression.h"
+#include "access/sequenceam.h"
#include "access/twophase.h"
#include "access/xlog_internal.h"
#include "access/xlogprefetcher.h"
@@ -4341,6 +4342,17 @@ struct config_string ConfigureNamesString[] =
check_default_table_access_method, NULL, NULL
},
+ {
+ {"default_sequence_access_method", PGC_USERSET, CLIENT_CONN_STATEMENT,
+ gettext_noop("Sets the default sequence access method for new sequences."),
+ NULL,
+ GUC_IS_NAME
+ },
+ &default_sequence_access_method,
+ DEFAULT_SEQUENCE_ACCESS_METHOD,
+ check_default_sequence_access_method, NULL, NULL
+ },
+
{
{"default_tablespace", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the default tablespace to create tables and indexes in."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index a9d8293474af..af0c0886adcc 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -750,6 +750,7 @@ autovacuum_worker_slots = 16 # autovacuum worker slots to allocate
# error
#search_path = '"$user", public' # schema names
#row_security = on
+#default_sequence_access_method = 'seqlocal'
#default_table_access_method = 'heap'
#default_tablespace = '' # a tablespace name, '' uses the default
#default_toast_compression = 'pglz' # 'pglz' or 'lz4'
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 7a06af48842d..d6d2a5940862 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -168,10 +168,12 @@ describeAccessMethods(const char *pattern, bool verbose)
"SELECT amname AS \"%s\",\n"
" CASE amtype"
" WHEN " CppAsString2(AMTYPE_INDEX) " THEN '%s'"
+ " WHEN " CppAsString2(AMTYPE_SEQUENCE) " THEN '%s'"
" WHEN " CppAsString2(AMTYPE_TABLE) " THEN '%s'"
" END AS \"%s\"",
gettext_noop("Name"),
gettext_noop("Index"),
+ gettext_noop("Sequence"),
gettext_noop("Table"),
gettext_noop("Type"));
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 8b10f2313f39..8ac13b26fe6a 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -2596,7 +2596,7 @@ match_previous_words(int pattern_id,
else if (Matches("ALTER", "SEQUENCE", MatchAny))
COMPLETE_WITH("AS", "INCREMENT", "MINVALUE", "MAXVALUE", "RESTART",
"START", "NO", "CACHE", "CYCLE", "SET", "OWNED BY",
- "OWNER TO", "RENAME TO");
+ "OWNER TO", "RENAME TO", "USING");
/* ALTER SEQUENCE <name> AS */
else if (TailMatches("ALTER", "SEQUENCE", MatchAny, "AS"))
COMPLETE_WITH_CS("smallint", "integer", "bigint");
@@ -3663,7 +3663,7 @@ match_previous_words(int pattern_id,
else if (TailMatches("CREATE", "SEQUENCE", MatchAny) ||
TailMatches("CREATE", "TEMP|TEMPORARY", "SEQUENCE", MatchAny))
COMPLETE_WITH("AS", "INCREMENT BY", "MINVALUE", "MAXVALUE", "NO",
- "CACHE", "CYCLE", "OWNED BY", "START WITH");
+ "CACHE", "CYCLE", "OWNED BY", "START WITH", "USING");
else if (TailMatches("CREATE", "SEQUENCE", MatchAny, "AS") ||
TailMatches("CREATE", "TEMP|TEMPORARY", "SEQUENCE", MatchAny, "AS"))
COMPLETE_WITH_CS("smallint", "integer", "bigint");
diff --git a/src/test/regress/expected/create_am.out b/src/test/regress/expected/create_am.out
index c1a951572512..784870e603d1 100644
--- a/src/test/regress/expected/create_am.out
+++ b/src/test/regress/expected/create_am.out
@@ -163,11 +163,6 @@ CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2;
ERROR: syntax error at or near "USING"
LINE 1: CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM ...
^
--- CREATE SEQUENCE doesn't support USING
-CREATE SEQUENCE tableam_seq_heap2 USING heap2;
-ERROR: syntax error at or near "USING"
-LINE 1: CREATE SEQUENCE tableam_seq_heap2 USING heap2;
- ^
-- CREATE MATERIALIZED VIEW does support USING
CREATE MATERIALIZED VIEW tableam_tblmv_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2;
SELECT f1 FROM tableam_tblmv_heap2 ORDER BY f1;
@@ -514,9 +509,12 @@ CREATE TABLE tableam_parted_heapx (a text, b int) PARTITION BY list (a);
CREATE TABLE tableam_parted_1_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('a', 'b');
-- but an explicitly set AM overrides it
CREATE TABLE tableam_parted_2_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('c', 'd') USING heap;
--- sequences, views and foreign servers shouldn't have an AM
-CREATE VIEW tableam_view_heapx AS SELECT * FROM tableam_tbl_heapx;
+-- sequences have an AM
+SET LOCAL default_sequence_access_method = 'seqlocal';
CREATE SEQUENCE tableam_seq_heapx;
+RESET default_sequence_access_method;
+-- views and foreign servers shouldn't have an AM
+CREATE VIEW tableam_view_heapx AS SELECT * FROM tableam_tbl_heapx;
CREATE FOREIGN DATA WRAPPER fdw_heap2 VALIDATOR postgresql_fdw_validator;
CREATE SERVER fs_heap2 FOREIGN DATA WRAPPER fdw_heap2 ;
CREATE FOREIGN table tableam_fdw_heapx () SERVER fs_heap2;
@@ -533,18 +531,18 @@ FROM pg_class AS pc
LEFT JOIN pg_am AS pa ON (pa.oid = pc.relam)
WHERE pc.relname LIKE 'tableam_%_heapx'
ORDER BY 3, 1, 2;
- relkind | amname | relname
----------+--------+-----------------------------
- f | | tableam_fdw_heapx
- r | heap2 | tableam_parted_1_heapx
- r | heap | tableam_parted_2_heapx
- p | | tableam_parted_heapx
- S | | tableam_seq_heapx
- r | heap2 | tableam_tbl_heapx
- r | heap2 | tableam_tblas_heapx
- m | heap2 | tableam_tblmv_heapx
- r | heap2 | tableam_tblselectinto_heapx
- v | | tableam_view_heapx
+ relkind | amname | relname
+---------+----------+-----------------------------
+ f | | tableam_fdw_heapx
+ r | heap2 | tableam_parted_1_heapx
+ r | heap | tableam_parted_2_heapx
+ p | | tableam_parted_heapx
+ S | seqlocal | tableam_seq_heapx
+ r | heap2 | tableam_tbl_heapx
+ r | heap2 | tableam_tblas_heapx
+ m | heap2 | tableam_tblmv_heapx
+ r | heap2 | tableam_tblselectinto_heapx
+ v | | tableam_view_heapx
(10 rows)
-- don't want to keep those tables, nor the default
@@ -574,3 +572,22 @@ table tableam_parted_b_heap2 depends on access method heap2
table tableam_parted_d_heap2 depends on access method heap2
HINT: Use DROP ... CASCADE to drop the dependent objects too.
-- we intentionally leave the objects created above alive, to verify pg_dump support
+-- Checks for sequence access methods
+-- Create new sequence access method which uses standard local handler
+CREATE ACCESS METHOD local2 TYPE SEQUENCE HANDLER seq_local_sequenceam_handler;
+-- Create and use sequence
+CREATE SEQUENCE test_seqam USING local2;
+SELECT nextval('test_seqam'::regclass);
+ nextval
+---------
+ 1
+(1 row)
+
+-- Try to drop and fail on dependency
+DROP ACCESS METHOD local2;
+ERROR: cannot drop access method local2 because other objects depend on it
+DETAIL: sequence test_seqam depends on access method local2
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
+-- And cleanup
+DROP SEQUENCE test_seqam;
+DROP ACCESS METHOD local2;
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 20bf9ea9cdf7..20b3d8520315 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1943,6 +1943,18 @@ WHERE p1.oid = a1.amhandler AND a1.amtype = 't' AND
-----+--------+-----+---------
(0 rows)
+-- check for sequence amhandler functions with the wrong signature
+SELECT a1.oid, a1.amname, p1.oid, p1.proname
+FROM pg_am AS a1, pg_proc AS p1
+WHERE p1.oid = a1.amhandler AND a1.amtype = 's' AND
+ (p1.prorettype != 'sequence_am_handler'::regtype
+ OR p1.proretset
+ OR p1.pronargs != 1
+ OR p1.proargtypes[0] != 'internal'::regtype);
+ oid | amname | oid | proname
+-----+--------+-----+---------
+(0 rows)
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
SELECT a1.amopfamily, a1.amopstrategy
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index a79325e8a2f7..19ade0eb7e62 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -5129,31 +5129,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
+ seqlocal | Sequence
+ 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
+ seqlocal | Sequence
+ spgist | Index
+(9 rows)
\dA h*
List of access methods
@@ -5178,32 +5180,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 |
+ seqlocal | Sequence | seq_local_sequenceam_handler | local sequence 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 |
+ seqlocal | Sequence | seq_local_sequenceam_handler | local sequence access method
+ spgist | Index | spghandler | SP-GiST index access method
+(9 rows)
\dA+ h*
List of access methods
diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out
index 943e56506bf1..f36e267c4b98 100644
--- a/src/test/regress/expected/type_sanity.out
+++ b/src/test/regress/expected/type_sanity.out
@@ -511,21 +511,21 @@ WHERE relkind NOT IN ('r', 'i', 'S', 't', 'v', 'm', 'c', 'f', 'p', 'I') OR
-----+---------
(0 rows)
--- All tables, indexes, partitioned indexes and matviews should have an
--- access method.
+-- All tables, indexes, partitioned indexes, matviews and sequences should have
+-- an access method.
SELECT c1.oid, c1.relname
FROM pg_class as c1
-WHERE c1.relkind NOT IN ('S', 'v', 'f', 'c', 'p') and
+WHERE c1.relkind NOT IN ('v', 'f', 'c', 'p') and
c1.relam = 0;
oid | relname
-----+---------
(0 rows)
--- Conversely, sequences, views, foreign tables, types and partitioned
--- tables shouldn't have them.
+-- Conversely, views, foreign tables, types and partitioned tables
+-- shouldn't have them.
SELECT c1.oid, c1.relname
FROM pg_class as c1
-WHERE c1.relkind IN ('S', 'v', 'f', 'c', 'p') and
+WHERE c1.relkind IN ('v', 'f', 'c', 'p') and
c1.relam != 0;
oid | relname
-----+---------
diff --git a/src/test/regress/sql/create_am.sql b/src/test/regress/sql/create_am.sql
index 754fe0c694bc..76a91cf8dd68 100644
--- a/src/test/regress/sql/create_am.sql
+++ b/src/test/regress/sql/create_am.sql
@@ -117,9 +117,6 @@ SELECT INTO tableam_tblselectinto_heap2 USING heap2 FROM tableam_tbl_heap2;
-- CREATE VIEW doesn't support USING
CREATE VIEW tableam_view_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2;
--- CREATE SEQUENCE doesn't support USING
-CREATE SEQUENCE tableam_seq_heap2 USING heap2;
-
-- CREATE MATERIALIZED VIEW does support USING
CREATE MATERIALIZED VIEW tableam_tblmv_heap2 USING heap2 AS SELECT * FROM tableam_tbl_heap2;
SELECT f1 FROM tableam_tblmv_heap2 ORDER BY f1;
@@ -327,9 +324,13 @@ CREATE TABLE tableam_parted_1_heapx PARTITION OF tableam_parted_heapx FOR VALUES
-- but an explicitly set AM overrides it
CREATE TABLE tableam_parted_2_heapx PARTITION OF tableam_parted_heapx FOR VALUES IN ('c', 'd') USING heap;
--- sequences, views and foreign servers shouldn't have an AM
-CREATE VIEW tableam_view_heapx AS SELECT * FROM tableam_tbl_heapx;
+-- sequences have an AM
+SET LOCAL default_sequence_access_method = 'seqlocal';
CREATE SEQUENCE tableam_seq_heapx;
+RESET default_sequence_access_method;
+
+-- views and foreign servers shouldn't have an AM
+CREATE VIEW tableam_view_heapx AS SELECT * FROM tableam_tbl_heapx;
CREATE FOREIGN DATA WRAPPER fdw_heap2 VALIDATOR postgresql_fdw_validator;
CREATE SERVER fs_heap2 FOREIGN DATA WRAPPER fdw_heap2 ;
CREATE FOREIGN table tableam_fdw_heapx () SERVER fs_heap2;
@@ -365,3 +366,16 @@ CREATE FOREIGN TABLE fp PARTITION OF tableam_parted_a_heap2 DEFAULT SERVER x;
DROP ACCESS METHOD heap2;
-- we intentionally leave the objects created above alive, to verify pg_dump support
+
+-- Checks for sequence access methods
+
+-- Create new sequence access method which uses standard local handler
+CREATE ACCESS METHOD local2 TYPE SEQUENCE HANDLER seq_local_sequenceam_handler;
+-- Create and use sequence
+CREATE SEQUENCE test_seqam USING local2;
+SELECT nextval('test_seqam'::regclass);
+-- Try to drop and fail on dependency
+DROP ACCESS METHOD local2;
+-- And cleanup
+DROP SEQUENCE test_seqam;
+DROP ACCESS METHOD local2;
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 2fb3a8528781..e60eeab33c02 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -1236,6 +1236,16 @@ WHERE p1.oid = a1.amhandler AND a1.amtype = 't' AND
OR p1.pronargs != 1
OR p1.proargtypes[0] != 'internal'::regtype);
+-- check for sequence amhandler functions with the wrong signature
+
+SELECT a1.oid, a1.amname, p1.oid, p1.proname
+FROM pg_am AS a1, pg_proc AS p1
+WHERE p1.oid = a1.amhandler AND a1.amtype = 's' AND
+ (p1.prorettype != 'sequence_am_handler'::regtype
+ OR p1.proretset
+ OR p1.pronargs != 1
+ OR p1.proargtypes[0] != 'internal'::regtype);
+
-- **************** pg_amop ****************
-- Look for illegal values in pg_amop fields
diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql
index df795759bb4c..dbaceb9fd2c8 100644
--- a/src/test/regress/sql/type_sanity.sql
+++ b/src/test/regress/sql/type_sanity.sql
@@ -370,18 +370,18 @@ WHERE relkind NOT IN ('r', 'i', 'S', 't', 'v', 'm', 'c', 'f', 'p', 'I') OR
relpersistence NOT IN ('p', 'u', 't') OR
relreplident NOT IN ('d', 'n', 'f', 'i');
--- All tables, indexes, partitioned indexes and matviews should have an
--- access method.
+-- All tables, indexes, partitioned indexes, matviews and sequences should have
+-- an access method.
SELECT c1.oid, c1.relname
FROM pg_class as c1
-WHERE c1.relkind NOT IN ('S', 'v', 'f', 'c', 'p') and
+WHERE c1.relkind NOT IN ('v', 'f', 'c', 'p') and
c1.relam = 0;
--- Conversely, sequences, views, foreign tables, types and partitioned
--- tables shouldn't have them.
+-- Conversely, views, foreign tables, types and partitioned tables
+-- shouldn't have them.
SELECT c1.oid, c1.relname
FROM pg_class as c1
-WHERE c1.relkind IN ('S', 'v', 'f', 'c', 'p') and
+WHERE c1.relkind IN ('v', 'f', 'c', 'p') and
c1.relam != 0;
-- Indexes and partitioned indexes should have AMs of type 'i'.
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index e6f2e93b2d6f..4bfb6434fe6f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2691,6 +2691,7 @@ SeqScanState
SeqTable
SeqTableData
SeqType
+SequenceAmRoutine
SequenceItem
SerCommitSeqNo
SerialControl
@@ -3764,6 +3765,7 @@ list_sort_comparator
loc_chunk
local_relopt
local_relopts
+local_sequence_magic
local_source
local_ts_iter
local_ts_radix_tree
@@ -4051,7 +4053,6 @@ scram_state_enum
script_error_callback_arg
security_class_t
sem_t
-sepgsql_context_info_t
sequence_magic
set_conn_altsock_func
set_conn_oauth_token_func
@@ -4278,6 +4279,7 @@ xl_heap_visible
xl_invalid_page
xl_invalid_page_key
xl_invalidations
+xl_local_seq_rec
xl_logical_message
xl_multi_insert_tuple
xl_multixact_create
@@ -4289,7 +4291,6 @@ xl_replorigin_drop
xl_replorigin_set
xl_restore_point
xl_running_xacts
-xl_seq_rec
xl_smgr_create
xl_smgr_truncate
xl_standby_lock
--
2.50.0