On 10/12/14 03:33, Petr Jelinek wrote:
On 24/11/14 12:16, Heikki Linnakangas wrote:

About the rough edges:
- The AlterSequence is not prettiest code around as we now have to
create new relation when sequence AM is changed and I don't know how to
do that nicely
- I am not sure if I did the locking, command order and dependency
handling in AlterSequence correcly

This version does AlterSequence differently and better. Didn't attach the gapless sequence again as that one is unchanged.


--
 Petr Jelinek                  http://www.2ndQuadrant.com/
 PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/src/backend/access/Makefile b/src/backend/access/Makefile
index 21721b4..818da15 100644
--- a/src/backend/access/Makefile
+++ b/src/backend/access/Makefile
@@ -8,6 +8,7 @@ subdir = src/backend/access
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS	    = brin common gin gist hash heap index nbtree rmgrdesc spgist transam
+SUBDIRS	    = brin common gin gist hash heap index nbtree rmgrdesc spgist \
+			  transam sequence
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index c16b38e..35818c0 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -321,6 +321,7 @@ static bool need_initialization = true;
 static void initialize_reloptions(void);
 static void parse_one_reloption(relopt_value *option, char *text_str,
 					int text_len, bool validate);
+static bytea *common_am_reloptions(RegProcedure amoptions, Datum reloptions, bool validate);
 
 /*
  * initialize_reloptions
@@ -821,7 +822,8 @@ untransformRelOptions(Datum options)
  * instead.
  *
  * tupdesc is pg_class' tuple descriptor.  amoptions is the amoptions regproc
- * in the case of the tuple corresponding to an index, or InvalidOid otherwise.
+ * in the case of the tuple corresponding to an index or sequence, InvalidOid
+ * otherwise.
  */
 bytea *
 extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
@@ -854,6 +856,9 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, Oid amoptions)
 		case RELKIND_INDEX:
 			options = index_reloptions(amoptions, datum, false);
 			break;
+		case RELKIND_SEQUENCE:
+			options = sequence_reloptions(amoptions, datum, false);
+			break;
 		case RELKIND_FOREIGN_TABLE:
 			options = NULL;
 			break;
@@ -1299,13 +1304,31 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
 
 /*
  * Parse options for indexes.
+ */
+bytea *
+index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
+{
+	return common_am_reloptions(amoptions, reloptions, validate);
+}
+
+/*
+ * Parse options for sequences.
+ */
+bytea *
+sequence_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
+{
+	return common_am_reloptions(amoptions, reloptions, validate);
+}
+
+/*
+ * Parse options for indexes or sequences.
  *
  *	amoptions	Oid of option parser
  *	reloptions	options as text[] datum
  *	validate	error flag
  */
-bytea *
-index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
+static bytea *
+common_am_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
 {
 	FmgrInfo	flinfo;
 	FunctionCallInfoData fcinfo;
diff --git a/src/backend/access/sequence/Makefile b/src/backend/access/sequence/Makefile
new file mode 100644
index 0000000..01a0dc8
--- /dev/null
+++ b/src/backend/access/sequence/Makefile
@@ -0,0 +1,17 @@
+#-------------------------------------------------------------------------
+#
+# Makefile--
+#    Makefile for access/sequence
+#
+# IDENTIFICATION
+#    src/backend/access/sequence/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/access/sequence
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS = seqam.o seqlocal.o
+
+include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/sequence/seqam.c b/src/backend/access/sequence/seqam.c
new file mode 100644
index 0000000..ce57f16
--- /dev/null
+++ b/src/backend/access/sequence/seqam.c
@@ -0,0 +1,428 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqam.c
+ *	  sequence access method routines
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/access/sequence/seqam.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.
+ *
+ * The SQL Standard assumes that each Sequence object is completely controlled
+ * from the current database node, preventing any form of clustering mechanisms
+ * from controlling behaviour. Sequence access methods are general purpose
+ * though designed specifically to address the needs of Sequences working as
+ * part of a multi-node "cluster", though that is not defined here, nor are
+ * there dependencies on anything outside of this module, nor any particular
+ * form of clustering.
+ *
+ * The SQL Standard behaviour, also the historical PostgreSQL behaviour, is
+ * referred to as the "Local" SeqAm. That is also the basic default.  Local
+ * SeqAm assumes that allocations from the sequence will be contiguous, so if
+ * user1 requests a range of values and is given 500-599 as values for their
+ * backend then the next user to make a request will be given a range starting
+ * with 600.
+ *
+ * The SeqAm mechanism allows us to override the Local behaviour, for use with
+ * clustering systems. When multiple masters can request ranges of values it
+ * would break the assumption of contiguous allocation. It seems likely that
+ * the SeqAm would also wish to control node-level caches for sequences to
+ * ensure good performance.  The CACHE option and other options may be
+ * overridden by the _alloc API call, if needed, though in general having
+ * cacheing per backend and per node seems desirable.
+ *
+ * SeqAm allows calls to allocate a new range of values, reset the sequence to
+ * a new value and to define options for the AM module.  The on-disk format of
+ * Sequences is the same for all AMs, except that each sequence has a SeqAm
+ * defined private-data column, am_data.
+ *
+ * We currently assume that there is no persistent state held within the SeqAm,
+ * so it is safe to ALTER the access method of an object without taking any
+ * special actions, as long as we hold an AccessExclusiveLock while we do that.
+ *
+ * SeqAMs work similarly to IndexAMs in many ways. pg_class.relam stores the
+ * Oid of the SeqAM, just as we do for IndexAm. The relcache stores AM
+ * information in much the same way for indexes and sequences, and management
+ * of options is similar also.
+ *
+ * Note that the SeqAM API calls are synchronous. It is up to the SeqAM to
+ * decide how that is handled, for example, whether there is a higher level
+ * cache at instance level to amortise network traffic in cluster.
+ *
+ * The SeqAM is identified by Oid of corresponding tuple in pg_seqam.  There is
+ * no syscache for pg_seqam, though the SeqAm data is stored on the relcache
+ * entry for the sequence.
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/seqam.h"
+#include "access/reloptions.h"
+#include "access/relscan.h"
+#include "access/transam.h"
+#include "access/xact.h"
+#include "catalog/pg_seqam.h"
+#include "utils/guc.h"
+#include "utils/rel.h"
+#include "utils/syscache.h"
+
+char	*default_seqam = NULL;
+
+#define GET_SEQAM_PROCEDURE(pname, missing_ok) \
+do { \
+	procedure = &seqrel->rd_aminfo->pname; \
+	if (!OidIsValid(procedure->fn_oid)) \
+	{ \
+		RegProcedure	procOid = seqrel->rd_seqam->pname; \
+		if (RegProcedureIsValid(procOid)) \
+			fmgr_info_cxt(procOid, procedure, seqrel->rd_indexcxt); \
+		else if (!missing_ok) \
+			elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
+	} \
+} while(0)
+
+/*-------------------------------------------------------------------------
+ *
+ *  Sequence Access Manager API
+ *
+ *  INTERFACE ROUTINES
+ *		seqam_extra_columns - get list of extra columns needed by the am
+ *		seqam_init			- initialize sequence, also used for resetting
+ *		seqam_alloc			- allocate a new range of values for the sequence
+ *		seqam_setval		- implements the setval SQL interface
+ *		seqam_seqparams		- process the standard sequence parameters
+ *		seqam_dump_state	- dump sequence state (for pg_dump)
+ *		seqam_restore_state - restore sequence state (for pg_dump)
+ *
+ *		sequence_reloptions	- process reloptions - located in reloptions.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * seqam_extra_columns - get custom column list
+ */
+List *
+seqam_extra_columns(Oid seqamid)
+{
+	FmgrInfo	procedure;
+	HeapTuple	tuple = NULL;
+	Form_pg_seqam seqamForm;
+	FunctionCallInfoData fcinfo;
+	Datum		ret;
+
+	tuple = SearchSysCache1(SEQAMOID, seqamid);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", seqamid);
+
+	seqamForm = (Form_pg_seqam) GETSTRUCT(tuple);
+
+	if (!RegProcedureIsValid(seqamForm->seqamextracols))
+		return NIL;
+
+	fmgr_info(seqamForm->seqamextracols, &procedure);
+
+	/*
+	 * have the seqam's proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, &procedure, 0, InvalidOid, NULL, NULL);
+
+	ret = FunctionCallInvoke(&fcinfo);
+
+	ReleaseSysCache(tuple);
+
+	return (List *)DatumGetPointer(ret);
+}
+
+/*
+ * seqam_init - initialize/replace custom sequence am values
+ */
+extern void
+seqam_init(Oid seqamid, List *seqparams,
+		   List *reloptions, bool is_init,
+		   Datum *values, bool *nulls)
+{
+	FmgrInfo	procedure;
+	HeapTuple	tuple = NULL;
+	Form_pg_seqam seqamForm;
+	FunctionCallInfoData fcinfo;
+	char	   *validnsps[] = {NULL, NULL};
+	Datum       reloptions_transformed;
+	bytea	   *reloptions_parsed;
+
+	tuple = SearchSysCache1(SEQAMOID, seqamid);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", seqamid);
+
+	seqamForm = (Form_pg_seqam) GETSTRUCT(tuple);
+
+	fmgr_info(seqamForm->seqaminit, &procedure);
+
+	/* Allow am specific options */
+	validnsps[0] = NameStr(seqamForm->seqamname);
+
+	/*
+	 *  Parse AM-specific options, convert to text array form,
+	 *  retrieve the AM-option function and then validate.
+	 */
+	reloptions_transformed = transformRelOptions((Datum) NULL, reloptions,
+												 NULL, validnsps, false,
+												 false);
+
+	reloptions_parsed = sequence_reloptions(seqamForm->seqamreloptions,
+											reloptions_transformed, true);
+
+	/*
+	 * Have the seqam's proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, &procedure, 5, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqparams);
+	fcinfo.arg[1] = PointerGetDatum(reloptions_parsed);
+	fcinfo.arg[2] = BoolGetDatum(is_init);
+	fcinfo.arg[3] = PointerGetDatum(values);
+	fcinfo.arg[4] = PointerGetDatum(nulls);
+	fcinfo.argnull[0] = seqparams == NULL;
+	fcinfo.argnull[1] = reloptions_parsed == NULL;
+	fcinfo.argnull[2] = false;
+	fcinfo.argnull[3] = false;
+	fcinfo.argnull[3] = false;
+
+	FunctionCallInvoke(&fcinfo);
+
+	ReleaseSysCache(tuple);
+}
+
+/*
+ * seqam_alloc - allocate sequence values in a sequence
+ */
+int64
+seqam_alloc(Relation seqrel, SequenceHandle *seqh, int64 nrequested,
+			int64 *last)
+{
+	FmgrInfo   *procedure;
+	FunctionCallInfoData fcinfo;
+	Datum		ret;
+
+	Assert(RelationIsValid(seqrel));
+	Assert(PointerIsValid(seqrel->rd_seqam));
+	Assert(OidIsValid(seqrel->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamalloc, false);
+
+	/*
+	 * have the seqam's alloc proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, procedure, 4, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqrel);
+	fcinfo.arg[1] = PointerGetDatum(seqh);
+	fcinfo.arg[2] = Int64GetDatum(nrequested);
+	fcinfo.arg[3] = PointerGetDatum(last);
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+	fcinfo.argnull[2] = false;
+	fcinfo.argnull[3] = false;
+
+	ret = FunctionCallInvoke(&fcinfo);
+	return DatumGetInt64(ret);
+}
+
+/*
+ * seqam_setval - set sequence values in a sequence
+ */
+void
+seqam_setval(Relation seqrel, SequenceHandle *seqh, int64 new_value)
+{
+	FmgrInfo   *procedure;
+	FunctionCallInfoData fcinfo;
+
+	Assert(RelationIsValid(seqrel));
+	Assert(PointerIsValid(seqrel->rd_seqam));
+	Assert(OidIsValid(seqrel->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamsetval, true);
+
+	if (!OidIsValid(procedure->fn_oid))
+		return;
+
+	/*
+	 * have the seqam's setval proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, procedure, 3, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqrel);
+	fcinfo.arg[1] = PointerGetDatum(seqh);
+	fcinfo.arg[2] = Int64GetDatum(new_value);
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+	fcinfo.argnull[2] = false;
+
+	FunctionCallInvoke(&fcinfo);
+}
+
+/*
+ * seqam_dump_state - pg_dump support
+ */
+char *
+seqam_dump_state(Relation seqrel, SequenceHandle *seqh)
+{
+	FmgrInfo	procedure;
+	Datum		ret;
+	FunctionCallInfoData fcinfo;
+
+	Assert(RelationIsValid(seqrel));
+	Assert(PointerIsValid(seqrel->rd_seqam));
+	Assert(OidIsValid(seqrel->rd_rel->relam));
+
+	fmgr_info(seqrel->rd_seqam->seqamdump, &procedure);
+
+	/*
+	 * have the seqam's setval proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, &procedure, 2, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqrel);
+	fcinfo.arg[1] = PointerGetDatum(seqh);
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+
+	ret = FunctionCallInvoke(&fcinfo);
+
+	return DatumGetCString(ret);
+}
+
+/*
+ * seqam_restore_state - restore from pg_dump
+ */
+void
+seqam_restore_state(Relation seqrel, SequenceHandle *seqh, char *state)
+{
+	FmgrInfo	procedure;
+	FunctionCallInfoData fcinfo;
+
+	Assert(RelationIsValid(seqrel));
+	Assert(PointerIsValid(seqrel->rd_seqam));
+	Assert(OidIsValid(seqrel->rd_rel->relam));
+
+	fmgr_info(seqrel->rd_seqam->seqamrestore, &procedure);
+
+	/*
+	 * have the seqam's setval proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, &procedure, 4, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqrel);
+	fcinfo.arg[1] = PointerGetDatum(seqh);
+	fcinfo.arg[2] = CStringGetDatum(state);
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+	fcinfo.argnull[2] = false;
+
+	FunctionCallInvoke(&fcinfo);
+}
+
+
+/*------------------------------------------------------------
+ *
+ * Sequence Access Manager management functions
+ *
+ *------------------------------------------------------------
+ */
+
+/* check_hook: validate new default_sequenceam */
+bool
+check_default_seqam(char **newval, void **extra, GucSource source)
+{
+	if (**newval == '\0')
+		return true;
+
+	/*
+	 * If we aren't inside a transaction, we cannot do database access so
+	 * cannot verify the name.	Must accept the value on faith.
+	 */
+	if (IsTransactionState())
+	{
+		if (!OidIsValid(get_seqam_oid(*newval, true)))
+		{
+			/*
+			 * When source == PGC_S_TEST, we are checking the argument of an
+			 * ALTER DATABASE SET or ALTER USER SET command.  Value may
+			 * be created later.  Because of that, issue a NOTICE if source ==
+			 * PGC_S_TEST, but accept the value anyway.
+			 */
+			if (source == PGC_S_TEST)
+			{
+				ereport(NOTICE,
+						(errcode(ERRCODE_UNDEFINED_OBJECT),
+						 errmsg("sequence manager \"%s\" does not exist",
+								*newval)));
+			}
+			else
+			{
+				GUC_check_errdetail("sequence manager \"%s\" does not exist.",
+									*newval);
+				return false;
+			}
+		}
+	}
+	return true;
+}
+
+/*
+ * GetDefaultSeqAM -- get the OID of the current default sequence AM
+ *
+ * This exists to hide (and possibly optimize the use of) the
+ * default_seqam GUC variable.
+ */
+Oid
+GetDefaultSeqAM(void)
+{
+	/* Fast path for default_tablespace == "" */
+	if (default_seqam == NULL || default_seqam[0] == '\0')
+		return LOCAL_SEQAM_OID;
+
+	return get_seqam_oid(default_seqam, false);
+}
+
+/*
+ * get_seqam_oid - given a sequence AM name, look up the OID
+ *
+ * If missing_ok is false, throw an error if SeqAM name not found.  If true,
+ * just return InvalidOid.
+ */
+Oid
+get_seqam_oid(const char *amname, bool missing_ok)
+{
+	Oid			result;
+	HeapTuple	tuple;
+
+	/* look up the access method */
+	tuple = SearchSysCache1(SEQAMNAME, PointerGetDatum(amname));
+
+	/* We assume that there can be at most one matching tuple */
+	if (HeapTupleIsValid(tuple))
+	{
+		result = HeapTupleGetOid(tuple);
+		ReleaseSysCache(tuple);
+	}
+	else
+		result = InvalidOid;
+
+	if (!OidIsValid(result) && !missing_ok)
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("squence access method \"%s\" does not exist",
+						amname)));
+	return result;
+}
diff --git a/src/backend/access/sequence/seqlocal.c b/src/backend/access/sequence/seqlocal.c
new file mode 100644
index 0000000..9cc5f11
--- /dev/null
+++ b/src/backend/access/sequence/seqlocal.c
@@ -0,0 +1,405 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqlocal.c
+ *	  Local sequence access manager
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/access/sequence/seqlocal.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/htup_details.h"
+#include "access/reloptions.h"
+#include "access/seqam.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/int8.h"
+
+/*
+ * We don't want to log each fetching of a value from a sequence,
+ * so we pre-log a few fetches in advance. In the event of
+ * crash we can lose (skip over) as many values as we pre-logged.
+ */
+#define SEQ_LOG_VALS	32
+
+/* Definition of additional columns for local sequence. */
+typedef struct FormLocalSequence
+{
+	FormData_pg_sequence seq;
+	int64		last_value;
+	int64		log_cnt;
+	bool		is_called;
+} FormLocalSequence;
+
+SeqAMColumnData seqam_local_cols[] = {
+	{"last_value", INT8OID, -1, true},
+	{"log_cnt", INT8OID, -1, true},
+	{"is_called", BOOLOID, -1, true}
+};
+#define SEQAM_LOCAL_EXTRACOLS_CNT 3
+#define SEQAM_LOCAL_COL_LASTVAL SEQ_COL_LASTCOL + 1
+#define SEQAM_LOCAL_COL_LOGCNT SEQ_COL_LASTCOL + 2
+#define SEQAM_LOCAL_COL_CALLED SEQ_COL_LASTCOL + 3
+
+/*
+ * seqam_local_extracols()
+ *
+ * Get definitions for extra columns needed by a local sequence
+ */
+Datum
+seqam_local_extracols(PG_FUNCTION_ARGS)
+{
+	List *ret = NIL;
+	int i;
+
+	for (i = 0; i < SEQAM_LOCAL_EXTRACOLS_CNT; i++)
+		ret = lappend(ret, &seqam_local_cols[i]);
+
+	PG_RETURN_POINTER(ret);
+}
+
+/*
+ * seqam_local_reloptions()
+ *
+ * Parse and verify the reloptions of a local sequence.
+ */
+Datum
+seqam_local_reloptions(PG_FUNCTION_ARGS)
+{
+	Datum       reloptions = PG_GETARG_DATUM(0);
+	bool        validate = PG_GETARG_BOOL(1);
+	bytea      *result;
+
+	result = default_reloptions(reloptions, validate, RELOPT_KIND_SEQUENCE);
+	if (result)
+		PG_RETURN_BYTEA_P(result);
+
+	PG_RETURN_NULL();
+}
+
+/*
+ * seqam_local_init()
+ *
+ * Initialize local sequence
+ */
+Datum
+seqam_local_init(PG_FUNCTION_ARGS)
+{
+	List *params = (List *)(PG_ARGISNULL(0) ? NULL : PG_GETARG_POINTER(0));
+	bool is_init = PG_GETARG_BOOL(2);
+	Datum *values = (Datum *)PG_GETARG_POINTER(3);
+	bool *nulls = (bool *)PG_GETARG_POINTER(4);
+
+	DefElem    *restart_value = NULL;
+	int64		last_value,
+				min_value,
+				max_value;
+	ListCell   *param;
+
+	foreach(param, params)
+	{
+		DefElem    *defel = (DefElem *) lfirst(param);
+		if (strcmp(defel->defname, "restart") == 0)
+		{
+			/* The redundacy check is done in the main sequence code. */
+			restart_value = defel;
+			break;
+		}
+	}
+
+	/* RESTART [WITH] */
+	if (restart_value != NULL)
+	{
+		Datum		last_value;
+
+		if (restart_value->arg != NULL)
+			last_value = defGetInt64(restart_value);
+		else
+			last_value = values[SEQ_COL_STARTVAL - 1];
+
+		values[SEQAM_LOCAL_COL_LASTVAL - 1] = last_value;
+		values[SEQAM_LOCAL_COL_CALLED - 1] = BoolGetDatum(false);
+	}
+	else if (is_init)
+	{
+		values[SEQAM_LOCAL_COL_LASTVAL - 1] = values[SEQ_COL_STARTVAL - 1];
+		values[SEQAM_LOCAL_COL_CALLED - 1] = BoolGetDatum(false);
+	}
+
+	last_value = DatumGetInt64(values[SEQAM_LOCAL_COL_LASTVAL - 1]);
+	min_value = DatumGetInt64(values[SEQ_COL_MINVALUE - 1]);
+	max_value = DatumGetInt64(values[SEQ_COL_MAXVALUE - 1]);
+
+	/* crosscheck RESTART (or current value, if changing MIN/MAX) */
+	if (last_value < min_value)
+	{
+		char		bufs[100],
+					bufm[100];
+
+		snprintf(bufs, sizeof(bufs), INT64_FORMAT, last_value);
+		snprintf(bufm, sizeof(bufm), INT64_FORMAT, min_value);
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+			   errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
+					  bufs, bufm)));
+	}
+	if (last_value > max_value)
+	{
+		char		bufs[100],
+					bufm[100];
+
+		snprintf(bufs, sizeof(bufs), INT64_FORMAT, last_value);
+		snprintf(bufm, sizeof(bufm), INT64_FORMAT, max_value);
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+			errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
+				   bufs, bufm)));
+	}
+
+	/* log_cnt */
+	values[SEQAM_LOCAL_COL_LOGCNT - 1] = Int64GetDatum(0);
+
+	nulls[SEQAM_LOCAL_COL_LASTVAL - 1] = false;
+	nulls[SEQAM_LOCAL_COL_LOGCNT - 1] = false;
+	nulls[SEQAM_LOCAL_COL_CALLED - 1] = false;
+
+	PG_RETURN_VOID();
+}
+
+/*
+ * seqam_local_alloc()
+ *
+ * Allocate new range of values for a local sequence.
+ */
+Datum
+seqam_local_alloc(PG_FUNCTION_ARGS)
+{
+	Relation	seqrel = (Relation) PG_GETARG_POINTER(0);
+	SequenceHandle	*seqh = (SequenceHandle*) PG_GETARG_POINTER(1);
+	int64	    nrequested = PG_GETARG_INT64(2);
+	int64	   *last = (int64 *) PG_GETARG_POINTER(3);
+	FormLocalSequence *seq;
+	int64		incby,
+				maxv,
+				minv,
+				log,
+				fetch,
+				result,
+				next,
+				rescnt = 0;
+	bool		is_cycled,
+				logit = false;
+
+	seq = (FormLocalSequence *) GETSTRUCT(sequence_read_tuple(seqh));
+
+	next = result = seq->last_value;
+	incby = seq->seq.increment_by;
+	maxv = seq->seq.max_value;
+	minv = seq->seq.min_value;
+	is_cycled = seq->seq.is_cycled;
+	fetch = nrequested;
+	log = seq->log_cnt;
+
+	/* We are returning last_value if not is_called so fetch one less value. */
+	if (!seq->is_called)
+	{
+		nrequested--;
+		fetch--;
+	}
+
+	/*
+	 * Decide whether we should emit a WAL log record.  If so, force up the
+	 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
+	 * cache.  (These will then be usable without logging.)
+	 *
+	 * If this is the first nextval after a checkpoint, we must force a new
+	 * WAL record to be written anyway, else replay starting from the
+	 * checkpoint would fail to advance the sequence past the logged values.
+	 * In this case we may as well fetch extra values.
+	 */
+	if (log < fetch || !seq->is_called)
+	{
+		/* Forced log to satisfy local demand for values. */
+		fetch = log = fetch + SEQ_LOG_VALS;
+		logit = true;
+	}
+	else if (sequence_needs_wal(seqh))
+	{
+		fetch = log = fetch + SEQ_LOG_VALS;
+		logit = true;
+	}
+
+	/* Fetch new result value if is_called. */
+	if (seq->is_called)
+	{
+		rescnt += sequence_increment(seqrel, &next, 1, minv, maxv, incby,
+									 is_cycled, true);
+		result = next;
+	}
+
+	/* Fetch as many values as was requested by backend. */
+	if (rescnt < nrequested)
+		rescnt += sequence_increment(seqrel, &next, nrequested-rescnt, minv,
+									maxv, incby, is_cycled, false);
+
+	/* Last value available for calling backend. */
+	*last = next;
+	/* Values we made available to calling backend can't be counted as cached. */
+	log -= rescnt;
+
+	/* We might need to fetch even more values for our own caching. */
+	if (rescnt < fetch)
+		rescnt += sequence_increment(seqrel, &next, fetch-rescnt, minv,
+									maxv, incby, is_cycled, false);
+
+	fetch -= rescnt;
+	log -= fetch;				/* adjust for any unfetched numbers */
+	Assert(log >= 0);
+
+	START_CRIT_SECTION();
+
+	/* Log our cached data. */
+	if (logit)
+	{
+		seq->last_value = next;
+		seq->is_called = true;
+		seq->log_cnt = 0;
+
+		sequence_save_tuple(seqh, NULL, true);
+	}
+
+	/* Now update sequence tuple to the intended final state */
+	seq->last_value = *last;		/* last fetched number */
+	seq->is_called = true;
+	seq->log_cnt = log;			/* how much is logged */
+
+	sequence_save_tuple(seqh, NULL, false);
+
+	END_CRIT_SECTION();
+
+	PG_RETURN_INT64(result);
+}
+
+/*
+ * seqam_local_setval()
+ *
+ * Set value of a local sequence
+ */
+Datum
+seqam_local_setval(PG_FUNCTION_ARGS)
+{
+	SequenceHandle	*seqh = (SequenceHandle*) PG_GETARG_POINTER(1);
+	int64	    next = PG_GETARG_INT64(2);
+	FormLocalSequence *seq;
+
+	seq = (FormLocalSequence *) GETSTRUCT(sequence_read_tuple(seqh));
+
+	seq->last_value = next;		/* last fetched number */
+	seq->is_called = true;
+	seq->log_cnt = 0;			/* how much is logged */
+
+	sequence_save_tuple(seqh, NULL, true);
+
+	PG_RETURN_VOID();
+}
+
+/*
+ * seqam_local_dump()
+ *
+ * Dump state of a local sequence (for pg_dump)
+ *
+ * Format is: '<last_value::bigint>, <is_called::boolean>'
+ */
+Datum
+seqam_local_dump(PG_FUNCTION_ARGS)
+{
+	SequenceHandle	   *seqh = (SequenceHandle*) PG_GETARG_POINTER(1);
+	FormLocalSequence  *seq;
+	char		buf[19 + 1 + 1 + 1 + 1]; /* int64 + colon + space + t/f + null byte */
+	char	   *result;
+
+
+	seq = (FormLocalSequence *) GETSTRUCT(sequence_read_tuple(seqh));
+
+	pg_lltoa(seq->last_value, buf);
+	strcat(buf, seq->is_called ? ", t" : ", f");
+	result = pstrdup(buf);
+
+	PG_RETURN_CSTRING(result);
+}
+
+/*
+ * seqam_local_restore()
+ *
+ * Restore previously dumpred state of local sequence (used by pg_dump)
+ *
+ * Format is: '<last_value::bigint>, <is_called::boolean>'
+*/
+Datum
+seqam_local_restore(PG_FUNCTION_ARGS)
+{
+	SequenceHandle	   *seqh = (SequenceHandle*) PG_GETARG_POINTER(1);
+	char			   *state = PG_GETARG_CSTRING(2);
+	FormLocalSequence  *seq;
+	int64				last_value;
+	bool				is_called;
+	char			   *buf;
+	char			   *ptr = state;
+	int					len;
+
+	/* Check that we can find comma. */
+	while (*ptr != ',' && *ptr != '\0')
+		ptr++;
+
+	if (*ptr == '\0')
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid input syntax for for local sequence state: \"%s\"",
+						state)));
+
+	/*
+	 * Copy the part of the string before comma into work buffer
+	 * for scanint8, it will handle leading/trailing whitespace correctly.
+	 */
+	len = ptr - state;
+	buf = palloc(len + 1);
+	memcpy(buf, state, len);
+	buf[len] = '\0';
+	scanint8(buf, false, &last_value);
+
+	/* Skip leading/trailing whitespace for parse_bool_with_len. */
+	ptr++;
+	while (isspace((unsigned char) *ptr))
+		ptr++;
+
+	len = strlen(ptr);
+	while (len > 0 && isspace((unsigned char) ptr[len - 1]))
+		len--;
+
+	/* Parse out the boolean */
+	if (!parse_bool_with_len(ptr, len, &is_called))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+				 errmsg("invalid input syntax for for local sequence state: \"%s\"",
+						state)));
+
+	pfree(buf);
+
+	seq = (FormLocalSequence *) GETSTRUCT(sequence_read_tuple(seqh));
+
+	seq->last_value = last_value;
+	seq->is_called = is_called;
+
+	sequence_save_tuple(seqh, NULL, true);
+
+	PG_RETURN_VOID();
+}
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index a403c64..147c571 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -35,7 +35,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_statistic.h pg_rewrite.h pg_trigger.h pg_event_trigger.h pg_description.h \
 	pg_cast.h pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
 	pg_database.h pg_db_role_setting.h pg_tablespace.h pg_pltemplate.h \
-	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
+	pg_authid.h pg_auth_members.h pg_seqam.h pg_shdepend.h pg_shdescription.h \
 	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
 	pg_ts_parser.h pg_ts_template.h pg_extension.h \
 	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index ba5b938..6689915 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -14,15 +14,21 @@
  */
 #include "postgres.h"
 
+#include "access/reloptions.h"
+#include "access/seqam.h"
+#include "access/transam.h"
 #include "access/htup_details.h"
 #include "access/multixact.h"
 #include "access/transam.h"
+#include "access/xact.h"
 #include "access/xlog.h"
 #include "access/xloginsert.h"
 #include "access/xlogutils.h"
 #include "catalog/dependency.h"
+#include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/objectaccess.h"
+#include "catalog/pg_seqam.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
 #include "commands/sequence.h"
@@ -35,19 +41,13 @@
 #include "storage/smgr.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/int8.h"
 #include "utils/lsyscache.h"
 #include "utils/resowner.h"
 #include "utils/syscache.h"
 
 
 /*
- * We don't want to log each fetching of a value from a sequence,
- * so we pre-log a few fetches in advance. In the event of
- * crash we can lose (skip over) as many values as we pre-logged.
- */
-#define SEQ_LOG_VALS	32
-
-/*
  * The "special area" of a sequence's buffer page looks like this.
  */
 #define SEQ_MAGIC	  0x1717
@@ -80,6 +80,14 @@ typedef SeqTableData *SeqTable;
 
 static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */
 
+struct SequenceHandle
+{
+	SeqTable	elm;
+	Relation	rel;
+	Buffer		buf;
+	HeapTuple	tup;
+};
+
 /*
  * last_used_seq is updated by nextval() to point to the last used
  * sequence.
@@ -90,13 +98,124 @@ static void fill_seq_with_data(Relation rel, HeapTuple tuple);
 static int64 nextval_internal(Oid relid);
 static Relation open_share_lock(SeqTable seq);
 static void create_seq_hashtable(void);
-static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
-static Form_pg_sequence read_seq_tuple(SeqTable elm, Relation rel,
-			   Buffer *buf, HeapTuple seqtuple);
 static void init_params(List *options, bool isInit,
 			Form_pg_sequence new, List **owned_by);
-static void do_setval(Oid relid, int64 next, bool iscalled);
 static void process_owned_by(Relation seqrel, List *owned_by);
+static void log_sequence_tuple(Relation seqrel, HeapTuple tuple,
+							   Buffer buf, Page page);
+static void seqrel_update_relam(Oid seqoid, Oid seqamid);
+static Oid get_new_seqam_oid(Oid oldAM, char *accessMethod);
+
+
+/*
+ * Build template column definition for a sequence relation.
+ */
+static ColumnDef *
+makeSeqColumnDef(void)
+{
+	ColumnDef  *coldef = makeNode(ColumnDef);
+
+	coldef->inhcount = 0;
+	coldef->is_local = true;
+	coldef->is_from_type = false;
+	coldef->storage = 0;
+	coldef->raw_default = NULL;
+	coldef->cooked_default = NULL;
+	coldef->collClause = NULL;
+	coldef->collOid = InvalidOid;
+	coldef->constraints = NIL;
+	coldef->location = -1;
+
+	return coldef;
+}
+
+/*
+ * Create the relation for sequence.
+ */
+static Oid
+DefineSequenceRelation(RangeVar *rel, List *cols,
+					   bool if_not_exists, Oid ownerId)
+{
+	CreateStmt *stmt = makeNode(CreateStmt);
+
+	stmt->relation = rel;
+	stmt->tableElts = cols;
+	stmt->inhRelations = NIL;
+	stmt->constraints = NIL;
+	stmt->options = NIL;
+	stmt->oncommit = ONCOMMIT_NOOP;
+	stmt->tablespacename = NULL;
+	stmt->if_not_exists = if_not_exists;
+
+	return DefineRelation(stmt, RELKIND_SEQUENCE, ownerId);
+}
+
+/*
+ * Add additional sequence am columns to the sequence column definition list.
+ */
+static List *
+BuildSeqColumnDefList(List *amcols)
+{
+	List	   *seqcols;
+	ListCell   *amcol;
+	int			colid;
+
+	seqcols = NIL;
+	for (colid = SEQ_COL_FIRSTCOL; colid <= SEQ_COL_LASTCOL; colid++)
+	{
+		ColumnDef  *coldef = makeSeqColumnDef();
+
+		coldef->is_not_null = true;
+
+		switch (colid)
+		{
+			case SEQ_COL_NAME:
+				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
+				coldef->colname = "sequence_name";
+				break;
+			case SEQ_COL_STARTVAL:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "start_value";
+				break;
+			case SEQ_COL_INCBY:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "increment_by";
+				break;
+			case SEQ_COL_MAXVALUE:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "max_value";
+				break;
+			case SEQ_COL_MINVALUE:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "min_value";
+				break;
+			case SEQ_COL_CACHE:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "cache_value";
+				break;
+			case SEQ_COL_CYCLE:
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
+				coldef->colname = "is_cycled";
+				break;
+		}
+		seqcols = lappend(seqcols, coldef);
+	}
+
+	foreach(amcol, amcols)
+	{
+		SeqAMColumn	amcolumn = lfirst(amcol);
+
+		ColumnDef  *coldef = makeSeqColumnDef();
+
+		coldef->typeName = makeTypeNameFromOid(amcolumn->coltyp,
+											   amcolumn->coltypmod);
+		coldef->colname = amcolumn->colname;
+		coldef->is_not_null = amcolumn->colnotnull;
+		seqcols = lappend(seqcols, coldef);
+	}
+
+	return seqcols;
+}
 
 
 /*
@@ -108,15 +227,17 @@ DefineSequence(CreateSeqStmt *seq)
 {
 	FormData_pg_sequence new;
 	List	   *owned_by;
-	CreateStmt *stmt = makeNode(CreateStmt);
 	Oid			seqoid;
+	Oid			seqamid;
 	Relation	rel;
 	HeapTuple	tuple;
 	TupleDesc	tupDesc;
-	Datum		value[SEQ_COL_LASTCOL];
-	bool		null[SEQ_COL_LASTCOL];
-	int			i;
+	Datum	   *value;
+	bool	   *null;
+	int			colid;
 	NameData	name;
+	List	   *seqcols,
+			   *amcols;
 
 	/* Unlogged sequences are not implemented -- not clear if useful. */
 	if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
@@ -142,104 +263,75 @@ DefineSequence(CreateSeqStmt *seq)
 		}
 	}
 
-	/* Check and set all option values */
+	/* Check and set all param values */
 	init_params(seq->options, true, &new, &owned_by);
 
+	/* Build column definitions. */
+	seqamid = get_new_seqam_oid(InvalidOid, seq->accessMethod);
+	amcols = seqam_extra_columns(seqamid);
+
+	seqcols = BuildSeqColumnDefList(amcols);
+
+	value = palloc0(list_length(seqcols) * sizeof(Datum));
+	null = palloc0(list_length(seqcols) * sizeof(bool));
+
 	/*
-	 * Create relation (and fill value[] and null[] for the tuple)
+	 * Fill value[] and null[] for the tuple.
 	 */
-	stmt->tableElts = NIL;
-	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
+	for (colid = SEQ_COL_FIRSTCOL; colid <= SEQ_COL_LASTCOL; colid++)
 	{
-		ColumnDef  *coldef = makeNode(ColumnDef);
+		null[colid - 1] = false;
 
-		coldef->inhcount = 0;
-		coldef->is_local = true;
-		coldef->is_not_null = true;
-		coldef->is_from_type = false;
-		coldef->storage = 0;
-		coldef->raw_default = NULL;
-		coldef->cooked_default = NULL;
-		coldef->collClause = NULL;
-		coldef->collOid = InvalidOid;
-		coldef->constraints = NIL;
-		coldef->location = -1;
-
-		null[i - 1] = false;
-
-		switch (i)
+		switch (colid)
 		{
 			case SEQ_COL_NAME:
-				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
-				coldef->colname = "sequence_name";
 				namestrcpy(&name, seq->sequence->relname);
-				value[i - 1] = NameGetDatum(&name);
-				break;
-			case SEQ_COL_LASTVAL:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "last_value";
-				value[i - 1] = Int64GetDatumFast(new.last_value);
+				value[colid - 1] = NameGetDatum(&name);
 				break;
 			case SEQ_COL_STARTVAL:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "start_value";
-				value[i - 1] = Int64GetDatumFast(new.start_value);
+				value[colid - 1] = Int64GetDatumFast(new.start_value);
 				break;
 			case SEQ_COL_INCBY:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "increment_by";
-				value[i - 1] = Int64GetDatumFast(new.increment_by);
+				value[colid - 1] = Int64GetDatumFast(new.increment_by);
 				break;
 			case SEQ_COL_MAXVALUE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "max_value";
-				value[i - 1] = Int64GetDatumFast(new.max_value);
+				value[colid - 1] = Int64GetDatumFast(new.max_value);
 				break;
 			case SEQ_COL_MINVALUE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "min_value";
-				value[i - 1] = Int64GetDatumFast(new.min_value);
+				value[colid - 1] = Int64GetDatumFast(new.min_value);
 				break;
 			case SEQ_COL_CACHE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "cache_value";
-				value[i - 1] = Int64GetDatumFast(new.cache_value);
-				break;
-			case SEQ_COL_LOG:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "log_cnt";
-				value[i - 1] = Int64GetDatum((int64) 0);
+				value[colid - 1] = Int64GetDatumFast(new.cache_value);
 				break;
 			case SEQ_COL_CYCLE:
-				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
-				coldef->colname = "is_cycled";
-				value[i - 1] = BoolGetDatum(new.is_cycled);
-				break;
-			case SEQ_COL_CALLED:
-				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
-				coldef->colname = "is_called";
-				value[i - 1] = BoolGetDatum(false);
+				value[colid - 1] = BoolGetDatum(new.is_cycled);
 				break;
 		}
-		stmt->tableElts = lappend(stmt->tableElts, coldef);
 	}
 
-	stmt->relation = seq->sequence;
-	stmt->inhRelations = NIL;
-	stmt->constraints = NIL;
-	stmt->options = NIL;
-	stmt->oncommit = ONCOMMIT_NOOP;
-	stmt->tablespacename = NULL;
-	stmt->if_not_exists = seq->if_not_exists;
+	/* Let AM fill the value[] and null[] for the tuple as well. */
+	seqam_init(seqamid, seq->options, seq->amoptions, true,
+			   value, null);
 
-	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId);
+	/* Create the sequence relation */
+	seqoid = DefineSequenceRelation(seq->sequence, seqcols,
+									seq->if_not_exists, seq->ownerId);
 	Assert(seqoid != InvalidOid);
 
+	/*
+	 * After we've created the sequence's relation in pg_class, update
+	 * the relam to a non-default value, if requested. We perform this
+	 * as a separate update to avoid invasive changes in normal code
+	 * paths and to keep the code similar between CREATE and ALTER.
+	 */
+	seqrel_update_relam(seqoid, seqamid);
+
 	rel = heap_open(seqoid, AccessExclusiveLock);
-	tupDesc = RelationGetDescr(rel);
 
 	/* now initialize the sequence's data */
+	tupDesc = RelationGetDescr(rel);
 	tuple = heap_form_tuple(tupDesc, value, null);
+
 	fill_seq_with_data(rel, tuple);
 
 	/* process OWNED BY if given */
@@ -266,56 +358,68 @@ DefineSequence(CreateSeqStmt *seq)
 void
 ResetSequence(Oid seq_relid)
 {
-	Relation	seq_rel;
-	SeqTable	elm;
-	Form_pg_sequence seq;
-	Buffer		buf;
-	HeapTupleData seqtuple;
 	HeapTuple	tuple;
+	HeapTuple	newtup;
+	Relation	seqrel;
+	TupleDesc	tupDesc;
+	Datum	   *values;
+	bool	   *nulls;
+	bool	   *replaces;
+	SequenceHandle  *seqh;
 
 	/*
-	 * Read the old sequence.  This does a bit more work than really
-	 * necessary, but it's simple, and we do want to double-check that it's
-	 * indeed a sequence.
+	 * Read and lock the old page.
 	 */
-	init_sequence(seq_relid, &elm, &seq_rel);
-	(void) read_seq_tuple(elm, seq_rel, &buf, &seqtuple);
+	seqh = sequence_open(seq_relid);
+	tuple = sequence_read_tuple(seqh);
 
 	/*
 	 * Copy the existing sequence tuple.
 	 */
-	tuple = heap_copytuple(&seqtuple);
+	tuple = heap_copytuple(tuple);
 
 	/* Now we're done with the old page */
-	UnlockReleaseBuffer(buf);
+	sequence_release_tuple(seqh);
 
 	/*
-	 * Modify the copied tuple to execute the restart (compare the RESTART
-	 * action in AlterSequence)
+	 * Tell AM to reset the sequence.
+	 * This fakes the ALTER SEQUENCE RESTART command from the
+	 * Sequence AM perspective.
 	 */
-	seq = (Form_pg_sequence) GETSTRUCT(tuple);
-	seq->last_value = seq->start_value;
-	seq->is_called = false;
-	seq->log_cnt = 0;
+	seqrel = seqh->rel;
+	tupDesc = RelationGetDescr(seqrel);
+	values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));
+	nulls = (bool *) palloc(tupDesc->natts * sizeof(bool));
+	replaces = (bool *) palloc(tupDesc->natts * sizeof(bool));
+	memset(replaces, true, tupDesc->natts * sizeof(bool));
+
+	heap_deform_tuple(tuple, tupDesc, values, nulls);
+
+	seqam_init(seqrel->rd_rel->relam,
+			   list_make1(makeDefElem("restart", NULL)), NULL, false,
+			   values, nulls);
+
+	newtup = heap_modify_tuple(tuple, tupDesc, values, nulls, replaces);
 
 	/*
 	 * Create a new storage file for the sequence.  We want to keep the
 	 * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs.
 	 * Same with relminmxid, since a sequence will never contain multixacts.
 	 */
-	RelationSetNewRelfilenode(seq_rel, seq_rel->rd_rel->relpersistence,
+	RelationSetNewRelfilenode(seqh->rel, seqh->rel->rd_rel->relpersistence,
 							  InvalidTransactionId, InvalidMultiXactId);
 
 	/*
 	 * Insert the modified tuple into the new storage file.
 	 */
-	fill_seq_with_data(seq_rel, tuple);
+	fill_seq_with_data(seqh->rel, newtup);
 
 	/* Clear local cache so that we don't think we have cached numbers */
 	/* Note that we do not change the currval() state */
-	elm->cached = elm->last;
+	seqh->elm->cached = seqh->elm->last;
 
-	relation_close(seq_rel, NoLock);
+	/* And we're done, close the sequence. */
+	sequence_close(seqh);
 }
 
 /*
@@ -368,23 +472,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 		elog(ERROR, "failed to add sequence tuple to page");
 
 	/* XLOG stuff */
-	if (RelationNeedsWAL(rel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
-
-		xlrec.node = rel->rd_node;
-
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
-		XLogRegisterData((char *) tuple->t_data, tuple->t_len);
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
-
-		PageSetLSN(page, recptr);
-	}
+	log_sequence_tuple(rel, tuple, buf, page);
 
 	END_CRIT_SECTION();
 
@@ -400,16 +488,23 @@ Oid
 AlterSequence(AlterSeqStmt *stmt)
 {
 	Oid			relid;
+	Oid			oldamid;
+	Oid			seqamid;
 	SeqTable	elm;
+	HeapTuple	tuple;
+	HeapTuple	newtup;
 	Relation	seqrel;
-	Buffer		buf;
-	HeapTupleData seqtuple;
-	Form_pg_sequence seq;
-	FormData_pg_sequence new;
+	Form_pg_sequence new;
 	List	   *owned_by;
+	TupleDesc	tupDesc;
+	Datum	   *values;
+	bool	   *nulls;
+	bool	   *replaces;
+	SequenceHandle *seqh;
 
 	/* Open and lock sequence. */
-	relid = RangeVarGetRelid(stmt->sequence, AccessShareLock, stmt->missing_ok);
+	relid = RangeVarGetRelid(stmt->sequence, AccessExclusiveLock, stmt->missing_ok);
+
 	if (relid == InvalidOid)
 	{
 		ereport(NOTICE,
@@ -418,7 +513,9 @@ AlterSequence(AlterSeqStmt *stmt)
 		return InvalidOid;
 	}
 
-	init_sequence(relid, &elm, &seqrel);
+	seqh = sequence_open(relid);
+	elm = seqh->elm;
+	seqrel = seqh->rel;
 
 	/* allow ALTER to sequence owner only */
 	if (!pg_class_ownercheck(relid, GetUserId()))
@@ -426,48 +523,98 @@ AlterSequence(AlterSeqStmt *stmt)
 					   stmt->sequence->relname);
 
 	/* lock page' buffer and read tuple into new sequence structure */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
+	tuple = sequence_read_tuple(seqh);
 
 	/* Copy old values of options into workspace */
-	memcpy(&new, seq, sizeof(FormData_pg_sequence));
+	tuple = heap_copytuple(tuple);
+	new = (Form_pg_sequence) GETSTRUCT(tuple);
 
 	/* Check and set new values */
-	init_params(stmt->options, false, &new, &owned_by);
+	init_params(stmt->options, false, new, &owned_by);
 
-	/* Clear local cache so that we don't think we have cached numbers */
-	/* Note that we do not change the currval() state */
-	elm->cached = elm->last;
+	tupDesc = RelationGetDescr(seqrel);
+	values = (Datum *) palloc(tupDesc->natts * sizeof(Datum));
+	nulls = (bool *) palloc(tupDesc->natts * sizeof(bool));
 
-	/* Now okay to update the on-disk tuple */
-	START_CRIT_SECTION();
+	heap_deform_tuple(tuple, tupDesc, values, nulls);
 
-	memcpy(seq, &new, sizeof(FormData_pg_sequence));
+	oldamid = seqrel->rd_rel->relam;
+	seqamid = get_new_seqam_oid(seqrel->rd_rel->relam, stmt->accessMethod);
 
-	MarkBufferDirty(buf);
-
-	/* XLOG stuff */
-	if (RelationNeedsWAL(seqrel))
+	/*
+	 * If we are changing sequence AM, we need to replace
+	 * the sequence relation.
+	 */
+	if (seqamid != oldamid)
 	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-		Page		page = BufferGetPage(buf);
+		List   *oldamcols = seqam_extra_columns(oldamid);
+		List   *newamcols = seqam_extra_columns(seqamid);
+		ListCell *amcol;
+		List   *atcmds = NIL;
 
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
+		sequence_release_tuple(seqh);
 
-		xlrec.node = seqrel->rd_node;
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
+		RelationSetNewRelfilenode(seqrel, seqrel->rd_rel->relpersistence,
+								  InvalidTransactionId, InvalidMultiXactId);
 
-		XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
+		foreach(amcol, oldamcols)
+		{
+			SeqAMColumn	amcolumn = lfirst(amcol);
+			AlterTableCmd *cmd = makeNode(AlterTableCmd);
+
+			cmd->subtype = AT_DropColumnFromSequence;
+			cmd->name = amcolumn->colname;
+			cmd->behavior = DROP_RESTRICT;
+			cmd->missing_ok = TRUE;
+			atcmds = lappend(atcmds, cmd);
+		}
 
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
+		foreach(amcol, newamcols)
+		{
+			SeqAMColumn	amcolumn = lfirst(amcol);
+			ColumnDef  *coldef = makeSeqColumnDef();
+			AlterTableCmd *cmd = makeNode(AlterTableCmd);
+
+			coldef->typeName = makeTypeNameFromOid(amcolumn->coltyp,
+												   amcolumn->coltypmod);
+			coldef->colname = amcolumn->colname;
+			coldef->is_not_null = amcolumn->colnotnull;
+
+			cmd->subtype = AT_AddColumnToSequence;
+			cmd->def = (Node *) coldef;
+			atcmds = lappend(atcmds, cmd);
+		}
 
-		PageSetLSN(page, recptr);
-	}
+		AlterTableInternal(relid, atcmds, false);
 
-	END_CRIT_SECTION();
+		/* Let sequence AM update the tuple. */
+		tupDesc = RelationGetDescr(seqrel);
 
-	UnlockReleaseBuffer(buf);
+		values = (Datum *) repalloc(values, tupDesc->natts * sizeof(Datum));
+		nulls = (bool *) repalloc(nulls, tupDesc->natts * sizeof(bool));
+
+		seqam_init(seqamid, stmt->options, stmt->amoptions, seqamid != oldamid,
+				   values, nulls);
+
+		newtup = heap_form_tuple(tupDesc, values, nulls);
+		fill_seq_with_data(seqh->rel, newtup);
+
+		seqrel_update_relam(relid, seqamid);
+	}
+	else
+	{
+		/* Let sequence AM update the tuple. */
+		replaces = (bool *) palloc(tupDesc->natts * sizeof(bool));
+		memset(replaces, true, tupDesc->natts * sizeof(bool));
+		seqam_init(seqamid, stmt->options, stmt->amoptions, seqamid != oldamid,
+				   values, nulls);
+		newtup = heap_modify_tuple(tuple, tupDesc, values, nulls, replaces);
+		sequence_save_tuple(seqh, newtup, true);
+	}
+
+	/* Clear local cache so that we don't think we have cached numbers */
+	/* Note that we do not change the currval() state */
+	elm->cached = elm->last;
 
 	/* process OWNED BY if given */
 	if (owned_by)
@@ -475,7 +622,7 @@ AlterSequence(AlterSeqStmt *stmt)
 
 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 
-	relation_close(seqrel, NoLock);
+	sequence_close(seqh);
 
 	return relid;
 }
@@ -516,29 +663,24 @@ nextval_oid(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(nextval_internal(relid));
 }
 
+/*
+ * Sequence AM independent part of nextval() that does permission checking,
+ * returns cached values and then calls out to the SeqAM specific nextval part.
+ */
 static int64
 nextval_internal(Oid relid)
 {
 	SeqTable	elm;
 	Relation	seqrel;
-	Buffer		buf;
-	Page		page;
-	HeapTupleData seqtuple;
-	Form_pg_sequence seq;
-	int64		incby,
-				maxv,
-				minv,
-				cache,
-				log,
-				fetch,
-				last;
-	int64		result,
-				next,
-				rescnt = 0;
-	bool		logit = false;
+	Form_pg_sequence seq_form;
+	int64		last,
+				result;
+	SequenceHandle *seqh;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	seqh = sequence_open(relid);
+	elm = seqh->elm;
+	seqrel = seqh->rel;
 
 	if (pg_class_aclcheck(elm->relid, GetUserId(),
 						  ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
@@ -556,121 +698,15 @@ nextval_internal(Oid relid)
 		Assert(elm->last_valid);
 		Assert(elm->increment != 0);
 		elm->last += elm->increment;
-		relation_close(seqrel, NoLock);
+		sequence_close(seqh);
 		last_used_seq = elm;
 		return elm->last;
 	}
 
 	/* lock page' buffer and read tuple */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
-	page = BufferGetPage(buf);
+	seq_form = (Form_pg_sequence) GETSTRUCT(sequence_read_tuple(seqh));
 
-	last = next = result = seq->last_value;
-	incby = seq->increment_by;
-	maxv = seq->max_value;
-	minv = seq->min_value;
-	fetch = cache = seq->cache_value;
-	log = seq->log_cnt;
-
-	if (!seq->is_called)
-	{
-		rescnt++;				/* return last_value if not is_called */
-		fetch--;
-	}
-
-	/*
-	 * Decide whether we should emit a WAL log record.  If so, force up the
-	 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
-	 * cache.  (These will then be usable without logging.)
-	 *
-	 * If this is the first nextval after a checkpoint, we must force a new
-	 * WAL record to be written anyway, else replay starting from the
-	 * checkpoint would fail to advance the sequence past the logged values.
-	 * In this case we may as well fetch extra values.
-	 */
-	if (log < fetch || !seq->is_called)
-	{
-		/* forced log to satisfy local demand for values */
-		fetch = log = fetch + SEQ_LOG_VALS;
-		logit = true;
-	}
-	else
-	{
-		XLogRecPtr	redoptr = GetRedoRecPtr();
-
-		if (PageGetLSN(page) <= redoptr)
-		{
-			/* last update of seq was before checkpoint */
-			fetch = log = fetch + SEQ_LOG_VALS;
-			logit = true;
-		}
-	}
-
-	while (fetch)				/* try to fetch cache [+ log ] numbers */
-	{
-		/*
-		 * Check MAXVALUE for ascending sequences and MINVALUE for descending
-		 * sequences
-		 */
-		if (incby > 0)
-		{
-			/* ascending sequence */
-			if ((maxv >= 0 && next > maxv - incby) ||
-				(maxv < 0 && next + incby > maxv))
-			{
-				if (rescnt > 0)
-					break;		/* stop fetching */
-				if (!seq->is_cycled)
-				{
-					char		buf[100];
-
-					snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
-					ereport(ERROR,
-						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
-								  RelationGetRelationName(seqrel), buf)));
-				}
-				next = minv;
-			}
-			else
-				next += incby;
-		}
-		else
-		{
-			/* descending sequence */
-			if ((minv < 0 && next < minv - incby) ||
-				(minv >= 0 && next + incby < minv))
-			{
-				if (rescnt > 0)
-					break;		/* stop fetching */
-				if (!seq->is_cycled)
-				{
-					char		buf[100];
-
-					snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
-					ereport(ERROR,
-						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
-								  RelationGetRelationName(seqrel), buf)));
-				}
-				next = maxv;
-			}
-			else
-				next += incby;
-		}
-		fetch--;
-		if (rescnt < cache)
-		{
-			log--;
-			rescnt++;
-			last = next;
-			if (rescnt == 1)	/* if it's first result - */
-				result = next;	/* it's what to return */
-		}
-	}
-
-	log -= fetch;				/* adjust for any unfetched numbers */
-	Assert(log >= 0);
+	result = seqam_alloc(seqrel, seqh, seq_form->cache_value, &last);
 
 	/* save info in local cache */
 	elm->last = result;			/* last returned number */
@@ -679,261 +715,119 @@ nextval_internal(Oid relid)
 
 	last_used_seq = elm;
 
-	/* ready to change the on-disk (or really, in-buffer) tuple */
-	START_CRIT_SECTION();
-
-	/*
-	 * We must mark the buffer dirty before doing XLogInsert(); see notes in
-	 * SyncOneBuffer().  However, we don't apply the desired changes just yet.
-	 * This looks like a violation of the buffer update protocol, but it is in
-	 * fact safe because we hold exclusive lock on the buffer.  Any other
-	 * process, including a checkpoint, that tries to examine the buffer
-	 * contents will block until we release the lock, and then will see the
-	 * final state that we install below.
-	 */
-	MarkBufferDirty(buf);
-
-	/* XLOG stuff */
-	if (logit && RelationNeedsWAL(seqrel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-
-		/*
-		 * We don't log the current state of the tuple, but rather the state
-		 * as it would appear after "log" more fetches.  This lets us skip
-		 * that many future WAL records, at the cost that we lose those
-		 * sequence values if we crash.
-		 */
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
-
-		/* set values that will be saved in xlog */
-		seq->last_value = next;
-		seq->is_called = true;
-		seq->log_cnt = 0;
-
-		xlrec.node = seqrel->rd_node;
-
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
-		XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
-
-		PageSetLSN(page, recptr);
-	}
-
-	/* Now update sequence tuple to the intended final state */
-	seq->last_value = last;		/* last fetched number */
-	seq->is_called = true;
-	seq->log_cnt = log;			/* how much is logged */
-
-	END_CRIT_SECTION();
-
-	UnlockReleaseBuffer(buf);
-
-	relation_close(seqrel, NoLock);
+	sequence_close(seqh);
 
 	return result;
 }
 
+
 Datum
 currval_oid(PG_FUNCTION_ARGS)
 {
 	Oid			relid = PG_GETARG_OID(0);
 	int64		result;
-	SeqTable	elm;
-	Relation	seqrel;
+	SequenceHandle *seqh;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	seqh = sequence_open(relid);
 
-	if (pg_class_aclcheck(elm->relid, GetUserId(),
+	if (pg_class_aclcheck(seqh->elm->relid, GetUserId(),
 						  ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied for sequence %s",
-						RelationGetRelationName(seqrel))));
-
-	if (!elm->last_valid)
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
-						RelationGetRelationName(seqrel))));
-
-	result = elm->last;
-
-	relation_close(seqrel, NoLock);
-
-	PG_RETURN_INT64(result);
-}
-
-Datum
-lastval(PG_FUNCTION_ARGS)
-{
-	Relation	seqrel;
-	int64		result;
-
-	if (last_used_seq == NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-				 errmsg("lastval is not yet defined in this session")));
-
-	/* Someone may have dropped the sequence since the last nextval() */
-	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
-		ereport(ERROR,
-				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-				 errmsg("lastval is not yet defined in this session")));
-
-	seqrel = open_share_lock(last_used_seq);
-
-	/* nextval() must have already been called for this sequence */
-	Assert(last_used_seq->last_valid);
-
-	if (pg_class_aclcheck(last_used_seq->relid, GetUserId(),
-						  ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("permission denied for sequence %s",
-						RelationGetRelationName(seqrel))));
-
-	result = last_used_seq->last;
-	relation_close(seqrel, NoLock);
-
-	PG_RETURN_INT64(result);
-}
-
-/*
- * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
- *
- * Note that the 3 arg version (which sets the is_called flag) is
- * only for use in pg_dump, and setting the is_called flag may not
- * work if multiple users are attached to the database and referencing
- * the sequence (unlikely if pg_dump is restoring it).
- *
- * It is necessary to have the 3 arg version so that pg_dump can
- * restore the state of a sequence exactly during data-only restores -
- * it is the only way to clear the is_called flag in an existing
- * sequence.
- */
-static void
-do_setval(Oid relid, int64 next, bool iscalled)
-{
-	SeqTable	elm;
-	Relation	seqrel;
-	Buffer		buf;
-	HeapTupleData seqtuple;
-	Form_pg_sequence seq;
-
-	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
-
-	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("permission denied for sequence %s",
-						RelationGetRelationName(seqrel))));
+						RelationGetRelationName(seqh->rel))));
 
-	/* read-only transactions may only modify temp sequences */
-	if (!seqrel->rd_islocaltemp)
-		PreventCommandIfReadOnly("setval()");
-
-	/* lock page' buffer and read tuple */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
-
-	if ((next < seq->min_value) || (next > seq->max_value))
-	{
-		char		bufv[100],
-					bufm[100],
-					bufx[100];
-
-		snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
-		snprintf(bufm, sizeof(bufm), INT64_FORMAT, seq->min_value);
-		snprintf(bufx, sizeof(bufx), INT64_FORMAT, seq->max_value);
+	if (!seqh->elm->last_valid)
 		ereport(ERROR,
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-				 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
-						bufv, RelationGetRelationName(seqrel),
-						bufm, bufx)));
-	}
-
-	/* Set the currval() state only if iscalled = true */
-	if (iscalled)
-	{
-		elm->last = next;		/* last returned number */
-		elm->last_valid = true;
-	}
-
-	/* In any case, forget any future cached numbers */
-	elm->cached = elm->last;
-
-	/* ready to change the on-disk (or really, in-buffer) tuple */
-	START_CRIT_SECTION();
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
+						RelationGetRelationName(seqh->rel))));
 
-	seq->last_value = next;		/* last fetched number */
-	seq->is_called = iscalled;
-	seq->log_cnt = 0;
+	result = seqh->elm->last;
 
-	MarkBufferDirty(buf);
+	sequence_close(seqh);
 
-	/* XLOG stuff */
-	if (RelationNeedsWAL(seqrel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-		Page		page = BufferGetPage(buf);
+	PG_RETURN_INT64(result);
+}
 
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
+Datum
+lastval(PG_FUNCTION_ARGS)
+{
+	Relation	seqrel;
+	int64		result;
 
-		xlrec.node = seqrel->rd_node;
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
-		XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
+	if (last_used_seq == NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("lastval is not yet defined in this session")));
 
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
+	/* Someone may have dropped the sequence since the last nextval() */
+	if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(last_used_seq->relid)))
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("lastval is not yet defined in this session")));
 
-		PageSetLSN(page, recptr);
-	}
+	seqrel = open_share_lock(last_used_seq);
 
-	END_CRIT_SECTION();
+	/* nextval() must have already been called for this sequence */
+	Assert(last_used_seq->last_valid);
 
-	UnlockReleaseBuffer(buf);
+	if (pg_class_aclcheck(last_used_seq->relid, GetUserId(),
+						  ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied for sequence %s",
+						RelationGetRelationName(seqrel))));
 
+	result = last_used_seq->last;
 	relation_close(seqrel, NoLock);
+
+	PG_RETURN_INT64(result);
 }
 
 /*
- * Implement the 2 arg setval procedure.
- * See do_setval for discussion.
+ * Implement the setval procedure.
  */
 Datum
 setval_oid(PG_FUNCTION_ARGS)
 {
 	Oid			relid = PG_GETARG_OID(0);
 	int64		next = PG_GETARG_INT64(1);
+	SeqTable	elm;
+	Relation	seqrel;
+	SequenceHandle *seqh;
 
-	do_setval(relid, next, true);
+	/* open and AccessShareLock sequence */
+	seqh = sequence_open(relid);
+	elm = seqh->elm;
+	seqrel = seqh->rel;
 
-	PG_RETURN_INT64(next);
-}
+	if (pg_class_aclcheck(elm->relid, GetUserId(),
+						  ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied for sequence %s",
+						RelationGetRelationName(seqrel))));
 
-/*
- * Implement the 3 arg setval procedure.
- * See do_setval for discussion.
- */
-Datum
-setval3_oid(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		next = PG_GETARG_INT64(1);
-	bool		iscalled = PG_GETARG_BOOL(2);
+	/* read-only transactions may only modify temp sequences */
+	if (!seqrel->rd_islocaltemp)
+		PreventCommandIfReadOnly("setval()");
 
-	do_setval(relid, next, iscalled);
+	seqam_setval(seqrel, seqh, next);
+
+	/* Reset local cached data */
+	elm->last = next;		/* last returned number */
+	elm->last_valid = true;
+	elm->cached = elm->last;
+
+	last_used_seq = elm;
+
+	sequence_close(seqh);
 
 	PG_RETURN_INT64(next);
 }
 
-
 /*
  * Open the sequence and acquire AccessShareLock if needed
  *
@@ -993,21 +887,21 @@ create_seq_hashtable(void)
 }
 
 /*
- * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
- * output parameters.
+ * Given a relation OID, open and share-lock the sequence.
  */
-static void
-init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
+SequenceHandle *
+sequence_open(Oid seq_relid)
 {
-	SeqTable	elm;
-	Relation	seqrel;
-	bool		found;
+	SequenceHandle *seqh;
+	SeqTable		elm;
+	Relation		seqrel;
+	bool			found;
 
 	/* Find or create a hash table entry for this sequence */
 	if (seqhashtab == NULL)
 		create_seq_hashtable();
 
-	elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
+	elm = (SeqTable) hash_search(seqhashtab, &seq_relid, HASH_ENTER, &found);
 
 	/*
 	 * Initialize the new hash table entry if it did not exist already.
@@ -1048,45 +942,60 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 		elm->cached = elm->last;
 	}
 
+	seqh = (SequenceHandle *) palloc(sizeof(SequenceHandle));
 	/* Return results */
-	*p_elm = elm;
-	*p_rel = seqrel;
+	seqh->elm = elm;
+	seqh->rel = seqrel;
+	seqh->buf = InvalidBuffer;
+	seqh->tup = NULL;
+
+	return seqh;
 }
 
+/*
+ * Given the sequence handle, unlock the page buffer and close the relation
+ */
+void
+sequence_close(SequenceHandle *seqh)
+{
+	sequence_release_tuple(seqh);
+
+	relation_close(seqh->rel, NoLock);
+}
 
 /*
  * Given an opened sequence relation, lock the page buffer and find the tuple
- *
- * *buf receives the reference to the pinned-and-ex-locked buffer
- * *seqtuple receives the reference to the sequence tuple proper
- *		(this arg should point to a local variable of type HeapTupleData)
- *
- * Function's return value points to the data payload of the tuple
  */
-static Form_pg_sequence
-read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
+HeapTuple
+sequence_read_tuple(SequenceHandle *seqh)
 {
 	Page		page;
+	Buffer		buf;
 	ItemId		lp;
 	sequence_magic *sm;
-	Form_pg_sequence seq;
+	Form_pg_sequence seq_form;
+
+	if (HeapTupleIsValid(seqh->tup))
+		return seqh->tup;
 
-	*buf = ReadBuffer(rel, 0);
-	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
+	seqh->tup = palloc0(HEAPTUPLESIZE);
+
+	seqh->buf = buf = ReadBuffer(seqh->rel, 0);
+	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
 
-	page = BufferGetPage(*buf);
+	page = BufferGetPage(buf);
 	sm = (sequence_magic *) PageGetSpecialPointer(page);
 
 	if (sm->magic != SEQ_MAGIC)
 		elog(ERROR, "bad magic number in sequence \"%s\": %08X",
-			 RelationGetRelationName(rel), sm->magic);
+			 RelationGetRelationName(seqh->rel), sm->magic);
 
 	lp = PageGetItemId(page, FirstOffsetNumber);
 	Assert(ItemIdIsNormal(lp));
 
-	/* Note we currently only bother to set these two fields of *seqtuple */
-	seqtuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
-	seqtuple->t_len = ItemIdGetLength(lp);
+	/* Note we currently only bother to set these two fields of seqh->tup */
+	seqh->tup->t_data = (HeapTupleHeader) PageGetItem(page, lp);
+	seqh->tup->t_len = ItemIdGetLength(lp);
 
 	/*
 	 * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on
@@ -1096,33 +1005,116 @@ read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
 	 * bit update, ie, don't bother to WAL-log it, since we can certainly do
 	 * this again if the update gets lost.
 	 */
-	Assert(!(seqtuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
-	if (HeapTupleHeaderGetRawXmax(seqtuple->t_data) != InvalidTransactionId)
+	Assert(!(seqh->tup->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
+	if (HeapTupleHeaderGetRawXmax(seqh->tup->t_data) != InvalidTransactionId)
 	{
-		HeapTupleHeaderSetXmax(seqtuple->t_data, InvalidTransactionId);
-		seqtuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
-		seqtuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
-		MarkBufferDirtyHint(*buf, true);
+		HeapTupleHeaderSetXmax(seqh->tup->t_data, InvalidTransactionId);
+		seqh->tup->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
+		seqh->tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
+		MarkBufferDirtyHint(buf, true);
 	}
 
-	seq = (Form_pg_sequence) GETSTRUCT(seqtuple);
+	seq_form = (Form_pg_sequence) GETSTRUCT(seqh->tup);
 
 	/* this is a handy place to update our copy of the increment */
-	elm->increment = seq->increment_by;
+	seqh->elm->increment = seq_form->increment_by;
+
+	return seqh->tup;
+}
+
+/*
+ * Update the page, optionally do WAL logging of the tuple
+ */
+void
+sequence_save_tuple(SequenceHandle *seqh, HeapTuple newtup, bool do_wal)
+{
+	Page	page;
+
+	Assert(HeapTupleIsValid(seqh->tup));
+
+	page = BufferGetPage(seqh->buf);
+
+	/* Only do tuple replacement if we got valid tuple on input. */
+	if (HeapTupleIsValid(newtup))
+	{
+		Page	temppage;
+
+		temppage = PageGetTempPageCopySpecial(page);
+
+		if (PageAddItem(temppage, (Item) newtup->t_data, newtup->t_len,
+						FirstOffsetNumber, false, false) == InvalidOffsetNumber)
+			elog(PANIC, "sequence_save_tuple: failed to add item to page");
+
+		PageSetLSN(temppage, PageGetLSN(page));
+
+		START_CRIT_SECTION();
 
-	return seq;
+		PageRestoreTempPage(temppage, page);
+		seqh->tup = newtup;
+		MarkBufferDirty(seqh->buf);
+
+		if (do_wal)
+			log_sequence_tuple(seqh->rel, newtup, seqh->buf, page);
+
+		END_CRIT_SECTION();
+	}
+	else
+	{
+		START_CRIT_SECTION();
+
+		MarkBufferDirty(seqh->buf);
+
+		if (do_wal)
+			log_sequence_tuple(seqh->rel, seqh->tup, seqh->buf, page);
+
+		END_CRIT_SECTION();
+	}
+}
+
+void
+sequence_release_tuple(SequenceHandle *seqh)
+{
+	/* Remove the tuple from cache */
+	if (HeapTupleIsValid(seqh->tup))
+	{
+		pfree(seqh->tup);
+		seqh->tup = NULL;
+	}
+
+	/* Release the page lock */
+	if (BufferIsValid(seqh->buf))
+	{
+		UnlockReleaseBuffer(seqh->buf);
+		seqh->buf = InvalidBuffer;
+	}
+}
+
+/*
+ * Returns true if sequence was not WAL logged since checkpoint
+ */
+bool
+sequence_needs_wal(SequenceHandle *seqh)
+{
+	Page		page;
+	XLogRecPtr	redoptr = GetRedoRecPtr();
+
+	Assert(BufferIsValid(seqh->buf));
+
+	page = BufferGetPage(seqh->buf);
+
+	return (PageGetLSN(page) <= redoptr);
 }
 
 /*
- * init_params: process the options list of CREATE or ALTER SEQUENCE,
+ * init_params: process the params list of CREATE or ALTER SEQUENCE,
  * and store the values into appropriate fields of *new.  Also set
- * *owned_by to any OWNED BY option, or to NIL if there is none.
+ * *owned_by to any OWNED BY param, or to NIL if there is none.
  *
- * If isInit is true, fill any unspecified options with default values;
- * otherwise, do not change existing options that aren't explicitly overridden.
+ * If isInit is true, fill any unspecified params with default values;
+ * otherwise, do not change existing params that aren't explicitly overridden.
  */
 static void
-init_params(List *options, bool isInit,
+init_params(List *params, bool isInit,
 			Form_pg_sequence new, List **owned_by)
 {
 	DefElem    *start_value = NULL;
@@ -1132,13 +1124,13 @@ init_params(List *options, bool isInit,
 	DefElem    *min_value = NULL;
 	DefElem    *cache_value = NULL;
 	DefElem    *is_cycled = NULL;
-	ListCell   *option;
+	ListCell   *param;
 
 	*owned_by = NIL;
 
-	foreach(option, options)
+	foreach(param, params)
 	{
-		DefElem    *defel = (DefElem *) lfirst(option);
+		DefElem    *defel = (DefElem *) lfirst(param);
 
 		if (strcmp(defel->defname, "increment") == 0)
 		{
@@ -1209,13 +1201,6 @@ init_params(List *options, bool isInit,
 				 defel->defname);
 	}
 
-	/*
-	 * We must reset log_cnt when isInit or when changing any parameters that
-	 * would affect future nextval allocations.
-	 */
-	if (isInit)
-		new->log_cnt = 0;
-
 	/* INCREMENT BY */
 	if (increment_by != NULL)
 	{
@@ -1224,7 +1209,6 @@ init_params(List *options, bool isInit,
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("INCREMENT must not be zero")));
-		new->log_cnt = 0;
 	}
 	else if (isInit)
 		new->increment_by = 1;
@@ -1234,7 +1218,6 @@ init_params(List *options, bool isInit,
 	{
 		new->is_cycled = intVal(is_cycled->arg);
 		Assert(BoolIsValid(new->is_cycled));
-		new->log_cnt = 0;
 	}
 	else if (isInit)
 		new->is_cycled = false;
@@ -1243,7 +1226,6 @@ init_params(List *options, bool isInit,
 	if (max_value != NULL && max_value->arg)
 	{
 		new->max_value = defGetInt64(max_value);
-		new->log_cnt = 0;
 	}
 	else if (isInit || max_value != NULL)
 	{
@@ -1251,14 +1233,12 @@ init_params(List *options, bool isInit,
 			new->max_value = SEQ_MAXVALUE;		/* ascending seq */
 		else
 			new->max_value = -1;	/* descending seq */
-		new->log_cnt = 0;
 	}
 
 	/* MINVALUE (null arg means NO MINVALUE) */
 	if (min_value != NULL && min_value->arg)
 	{
 		new->min_value = defGetInt64(min_value);
-		new->log_cnt = 0;
 	}
 	else if (isInit || min_value != NULL)
 	{
@@ -1266,7 +1246,6 @@ init_params(List *options, bool isInit,
 			new->min_value = 1; /* ascending seq */
 		else
 			new->min_value = SEQ_MINVALUE;		/* descending seq */
-		new->log_cnt = 0;
 	}
 
 	/* crosscheck min/max */
@@ -1320,48 +1299,6 @@ init_params(List *options, bool isInit,
 					 bufs, bufm)));
 	}
 
-	/* RESTART [WITH] */
-	if (restart_value != NULL)
-	{
-		if (restart_value->arg != NULL)
-			new->last_value = defGetInt64(restart_value);
-		else
-			new->last_value = new->start_value;
-		new->is_called = false;
-		new->log_cnt = 0;
-	}
-	else if (isInit)
-	{
-		new->last_value = new->start_value;
-		new->is_called = false;
-	}
-
-	/* crosscheck RESTART (or current value, if changing MIN/MAX) */
-	if (new->last_value < new->min_value)
-	{
-		char		bufs[100],
-					bufm[100];
-
-		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
-		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			   errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
-					  bufs, bufm)));
-	}
-	if (new->last_value > new->max_value)
-	{
-		char		bufs[100],
-					bufm[100];
-
-		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
-		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
-				   bufs, bufm)));
-	}
-
 	/* CACHE */
 	if (cache_value != NULL)
 	{
@@ -1376,14 +1313,13 @@ init_params(List *options, bool isInit,
 					 errmsg("CACHE (%s) must be greater than zero",
 							buf)));
 		}
-		new->log_cnt = 0;
 	}
 	else if (isInit)
 		new->cache_value = 1;
 }
 
 /*
- * Process an OWNED BY option for CREATE/ALTER SEQUENCE
+ * Process an OWNED BY param for CREATE/ALTER SEQUENCE
  *
  * Ownership permissions on the sequence are already checked,
  * but if we are establishing a new owned-by dependency, we must
@@ -1399,8 +1335,7 @@ process_owned_by(Relation seqrel, List *owned_by)
 
 	nnames = list_length(owned_by);
 	Assert(nnames > 0);
-	if (nnames == 1)
-	{
+	if (nnames == 1)	{
 		/* Must be OWNED BY NONE */
 		if (strcmp(strVal(linitial(owned_by)), "none") != 0)
 			ereport(ERROR,
@@ -1487,20 +1422,17 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	TupleDesc	tupdesc;
 	Datum		values[5];
 	bool		isnull[5];
-	SeqTable	elm;
-	Relation	seqrel;
-	Buffer		buf;
-	HeapTupleData seqtuple;
 	Form_pg_sequence seq;
+	SequenceHandle  *seqh;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	seqh = sequence_open(relid);
 
 	if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied for sequence %s",
-						RelationGetRelationName(seqrel))));
+						RelationGetRelationName(seqh->rel))));
 
 	tupdesc = CreateTemplateTupleDesc(5, false);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
@@ -1518,7 +1450,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	memset(isnull, 0, sizeof(isnull));
 
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
+	seq = (Form_pg_sequence) GETSTRUCT(sequence_read_tuple(seqh));
 
 	values[0] = Int64GetDatum(seq->start_value);
 	values[1] = Int64GetDatum(seq->min_value);
@@ -1526,12 +1458,99 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	values[3] = Int64GetDatum(seq->increment_by);
 	values[4] = BoolGetDatum(seq->is_cycled);
 
-	UnlockReleaseBuffer(buf);
-	relation_close(seqrel, NoLock);
+	sequence_close(seqh);
 
 	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
+Datum
+pg_sequence_dump_state(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	char	   *result;
+	SequenceHandle  *seqh;
+
+	seqh = sequence_open(relid);
+
+	result = seqam_dump_state(seqh->rel, seqh);
+
+	sequence_close(seqh);
+
+	PG_RETURN_CSTRING(result);
+}
+
+Datum
+pg_sequence_restore_state(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	char	   *state = PG_GETARG_CSTRING(1);
+	SequenceHandle  *seqh;
+
+	seqh = sequence_open(relid);
+
+	seqam_restore_state(seqh->rel, seqh, state);
+
+	sequence_close(seqh);
+
+	PG_RETURN_VOID();
+}
+
+/*
+ * Update pg_class row for sequence to record change in relam.
+ *
+ * Call only while holding AccessExclusiveLock on sequence.
+ *
+ * Note that this is a transactional update of pg_class, rather
+ * than a non-transactional update of the tuple in the sequence's
+ * heap, as occurs elsewhere in this module.
+ */
+static void
+seqrel_update_relam(Oid seqoid, Oid seqamid)
+{
+	Relation	rd;
+	HeapTuple	ctup;
+	Form_pg_class pgcform;
+
+	rd = heap_open(RelationRelationId, RowExclusiveLock);
+
+	/* Fetch a copy of the tuple to scribble on */
+	ctup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(seqoid));
+	if (!HeapTupleIsValid(ctup))
+		elog(ERROR, "pg_class entry for sequence %u unavailable",
+						seqoid);
+	pgcform = (Form_pg_class) GETSTRUCT(ctup);
+
+	if (pgcform->relam != seqamid)
+	{
+		pgcform->relam = seqamid;
+		simple_heap_update(rd, &ctup->t_self, ctup);
+		CatalogUpdateIndexes(rd, ctup);
+	}
+
+	heap_freetuple(ctup);
+	heap_close(rd, RowExclusiveLock);
+	CommandCounterIncrement();
+}
+
+static void
+log_sequence_tuple(Relation seqrel, HeapTuple tuple,
+				   Buffer buf, Page page)
+{
+	xl_seq_rec	xlrec;
+	XLogRecPtr	recptr;
+
+	XLogBeginInsert();
+	XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
+
+	xlrec.node = seqrel->rd_node;
+
+	XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
+	XLogRegisterData((char *) tuple->t_data, tuple->t_len);
+
+	recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
+
+	PageSetLSN(page, recptr);
+}
 
 void
 seq_redo(XLogReaderState *record)
@@ -1583,6 +1602,7 @@ seq_redo(XLogReaderState *record)
 	pfree(localpage);
 }
 
+
 /*
  * Flush cached sequence information.
  */
@@ -1597,3 +1617,92 @@ ResetSequenceCaches(void)
 
 	last_used_seq = NULL;
 }
+
+static Oid
+get_new_seqam_oid(Oid oldAM, char *accessMethod)
+{
+
+	if (oldAM && accessMethod == NULL)
+		return oldAM;
+	else if (accessMethod == NULL || strcmp(accessMethod, DEFAULT_SEQAM) == 0)
+		return GetDefaultSeqAM();
+	else
+		return get_seqam_oid(accessMethod, false);
+}
+
+
+int64
+sequence_increment(Relation seqrel, int64 *value, int64 incnum, int64 minv,
+				   int64 maxv, int64 incby, bool is_cycled, bool report_errors)
+{
+	int64 next = *value;
+	int64 rescnt = 0;
+
+	while (incnum)
+	{
+		/*
+		 * Check MAXVALUE for ascending sequences and MINVALUE for descending
+		 * sequences
+		 */
+		if (incby > 0)
+		{
+			/* ascending sequence */
+			if ((maxv >= 0 && next > maxv - incby) ||
+				(maxv < 0 && next + incby > maxv))
+			{
+				/*
+				 * We were asked to not report errors, return without incrementing
+				 * and let the caller handle it.
+				 */
+				if (!report_errors)
+					return rescnt;
+				if (!is_cycled)
+				{
+					char		buf[100];
+
+					snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
+					ereport(ERROR,
+						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
+								  RelationGetRelationName(seqrel), buf)));
+				}
+				next = minv;
+			}
+			else
+				next += incby;
+		}
+		else
+		{
+			/* descending sequence */
+			if ((minv < 0 && next < minv - incby) ||
+				(minv >= 0 && next + incby < minv))
+			{
+				/*
+				 * We were asked to not report errors, return without incrementing
+				 * and let the caller handle it.
+				 */
+				if (!report_errors)
+					return rescnt;
+				if (!is_cycled)
+				{
+					char		buf[100];
+
+					snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
+					ereport(ERROR,
+						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+						   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
+								  RelationGetRelationName(seqrel), buf)));
+				}
+				next = maxv;
+			}
+			else
+				next += incby;
+		}
+		rescnt++;
+		incnum--;
+	}
+
+	*value = next;
+
+	return rescnt;
+}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1e737a0..f15c0c4 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -265,6 +265,7 @@ struct DropRelationCallbackState
 #define		ATT_INDEX				0x0008
 #define		ATT_COMPOSITE_TYPE		0x0010
 #define		ATT_FOREIGN_TABLE		0x0020
+#define		ATT_SEQUENCE			0x0040
 
 static void truncate_check_rel(Relation rel);
 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
@@ -2838,6 +2839,8 @@ AlterTableGetLockLevel(List *cmds)
 				 */
 			case AT_DropColumn:	/* change visible to SELECT */
 			case AT_AddColumnToView:	/* CREATE VIEW */
+			case AT_AddColumnToSequence:	/* ALTER SEQUENCE USING */
+			case AT_DropColumnFromSequence:	/* ALTER SEQUENCE USING */
 			case AT_DropOids:	/* calls AT_DropColumn */
 			case AT_EnableAlwaysRule:	/* may change SELECT rules */
 			case AT_EnableReplicaRule:	/* may change SELECT rules */
@@ -3097,6 +3100,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			/* Recursion occurs during execution phase */
 			pass = AT_PASS_ADD_COL;
 			break;
+		case AT_AddColumnToSequence:	/* add column via ALTER SEQUENCE
+										   USING */
+			ATSimplePermissions(rel, ATT_SEQUENCE);
+			ATPrepAddColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
+			/* This command never recurses */
+			pass = AT_PASS_MISC;
+			break;
 		case AT_ColumnDefault:	/* ALTER COLUMN DEFAULT */
 
 			/*
@@ -3147,6 +3157,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			/* Recursion occurs during execution phase */
 			pass = AT_PASS_DROP;
 			break;
+		case AT_DropColumnFromSequence:	/* drop column via ALTER SEQUENCE
+										   USING */
+			ATSimplePermissions(rel, ATT_SEQUENCE);
+			ATPrepDropColumn(wqueue, rel, recurse, recursing, cmd, lockmode);
+			/* This command never recurses */
+			pass = AT_PASS_MISC;
+			break;
 		case AT_AddIndex:		/* ADD INDEX */
 			ATSimplePermissions(rel, ATT_TABLE);
 			/* This command never recurses */
@@ -3399,6 +3416,8 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 		case AT_AddColumn:		/* ADD COLUMN */
 		case AT_AddColumnToView:		/* add column via CREATE OR REPLACE
 										 * VIEW */
+		case AT_AddColumnToSequence:	/* add column via ALTER SEQUENCE
+										   USING */
 			ATExecAddColumn(wqueue, tab, rel, (ColumnDef *) cmd->def,
 							false, false, false, lockmode);
 			break;
@@ -3428,6 +3447,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			ATExecSetStorage(rel, cmd->name, cmd->def, lockmode);
 			break;
 		case AT_DropColumn:		/* DROP COLUMN */
+		case AT_DropColumnFromSequence:		/* ALTER SEQUENCE USING */
 			ATExecDropColumn(wqueue, rel, cmd->name,
 					 cmd->behavior, false, false, cmd->missing_ok, lockmode);
 			break;
@@ -4211,6 +4231,9 @@ ATSimplePermissions(Relation rel, int allowed_targets)
 		case RELKIND_FOREIGN_TABLE:
 			actual_target = ATT_FOREIGN_TABLE;
 			break;
+		case RELKIND_SEQUENCE:
+			actual_target = ATT_SEQUENCE;
+			break;
 		default:
 			actual_target = 0;
 			break;
@@ -4275,6 +4298,9 @@ ATWrongRelkindError(Relation rel, int allowed_targets)
 		case ATT_FOREIGN_TABLE:
 			msg = _("\"%s\" is not a foreign table");
 			break;
+		case ATT_SEQUENCE:
+			msg = _("\"%s\" is not a sequence");
+			break;
 		default:
 			/* shouldn't get here, add all necessary cases above */
 			msg = _("\"%s\" is of the wrong type");
@@ -9046,6 +9072,9 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 		case RELKIND_INDEX:
 			(void) index_reloptions(rel->rd_am->amoptions, newOptions, true);
 			break;
+		case RELKIND_SEQUENCE:
+			(void) sequence_reloptions(rel->rd_am->amoptions, newOptions, true);
+			break;
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 6b1bf7b..c9f7f8e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3361,7 +3361,9 @@ _copyCreateSeqStmt(const CreateSeqStmt *from)
 
 	COPY_NODE_FIELD(sequence);
 	COPY_NODE_FIELD(options);
+	COPY_NODE_FIELD(amoptions);
 	COPY_SCALAR_FIELD(ownerId);
+	COPY_STRING_FIELD(accessMethod);
 	COPY_SCALAR_FIELD(if_not_exists);
 
 	return newnode;
@@ -3374,7 +3376,9 @@ _copyAlterSeqStmt(const AlterSeqStmt *from)
 
 	COPY_NODE_FIELD(sequence);
 	COPY_NODE_FIELD(options);
+	COPY_NODE_FIELD(amoptions);
 	COPY_SCALAR_FIELD(missing_ok);
+	COPY_STRING_FIELD(accessMethod);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d5db71d..90e765c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1567,7 +1567,9 @@ _equalCreateSeqStmt(const CreateSeqStmt *a, const CreateSeqStmt *b)
 {
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
+	COMPARE_NODE_FIELD(amoptions);
 	COMPARE_SCALAR_FIELD(ownerId);
+	COMPARE_STRING_FIELD(accessMethod);
 	COMPARE_SCALAR_FIELD(if_not_exists);
 
 	return true;
@@ -1578,7 +1580,9 @@ _equalAlterSeqStmt(const AlterSeqStmt *a, const AlterSeqStmt *b)
 {
 	COMPARE_NODE_FIELD(sequence);
 	COMPARE_NODE_FIELD(options);
+	COMPARE_NODE_FIELD(amoptions);
 	COMPARE_SCALAR_FIELD(missing_ok);
+	COMPARE_STRING_FIELD(accessMethod);
 
 	return true;
 }
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 4b5009b..56ff30b 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -51,6 +51,7 @@
 
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_seqam.h"
 #include "catalog/pg_trigger.h"
 #include "commands/defrem.h"
 #include "commands/trigger.h"
@@ -3503,7 +3504,33 @@ CreateSeqStmt:
 					CreateSeqStmt *n = makeNode(CreateSeqStmt);
 					$4->relpersistence = $2;
 					n->sequence = $4;
+					n->accessMethod = DEFAULT_SEQAM;
 					n->options = $5;
+					n->amoptions = NIL;
+					n->ownerId = InvalidOid;
+					$$ = (Node *)n;
+				}
+			| CREATE OptTemp SEQUENCE qualified_name OptSeqOptList
+				USING access_method
+				{
+					CreateSeqStmt *n = makeNode(CreateSeqStmt);
+					$4->relpersistence = $2;
+					n->sequence = $4;
+					n->accessMethod = $7;
+					n->options = $5;
+					n->amoptions = NIL;
+					n->ownerId = InvalidOid;
+					$$ = (Node *)n;
+				}
+			| CREATE OptTemp SEQUENCE qualified_name OptSeqOptList
+				USING access_method WITH reloptions
+				{
+					CreateSeqStmt *n = makeNode(CreateSeqStmt);
+					$4->relpersistence = $2;
+					n->sequence = $4;
+					n->accessMethod = $7;
+					n->options = $5;
+					n->amoptions = $9;
 					n->ownerId = InvalidOid;
 					n->if_not_exists = false;
 					$$ = (Node *)n;
@@ -3525,7 +3552,31 @@ AlterSeqStmt:
 				{
 					AlterSeqStmt *n = makeNode(AlterSeqStmt);
 					n->sequence = $3;
+					n->accessMethod = NULL;
+					n->options = $4;
+					n->amoptions = NIL;
+					n->missing_ok = false;
+					$$ = (Node *)n;
+				}
+			| ALTER SEQUENCE qualified_name OptSeqOptList
+				USING access_method
+				{
+					AlterSeqStmt *n = makeNode(AlterSeqStmt);
+					n->sequence = $3;
+					n->accessMethod = $6;
 					n->options = $4;
+					n->amoptions = NIL;
+					n->missing_ok = false;
+					$$ = (Node *)n;
+				}
+			| ALTER SEQUENCE qualified_name OptSeqOptList
+				USING access_method WITH reloptions
+				{
+					AlterSeqStmt *n = makeNode(AlterSeqStmt);
+					n->sequence = $3;
+					n->accessMethod = $6;
+					n->options = $4;
+					n->amoptions = $8;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -3533,11 +3584,34 @@ AlterSeqStmt:
 				{
 					AlterSeqStmt *n = makeNode(AlterSeqStmt);
 					n->sequence = $5;
+					n->accessMethod = NULL;
 					n->options = $6;
+					n->amoptions = NIL;
+					n->missing_ok = true;
+					$$ = (Node *)n;
+				}
+			| ALTER SEQUENCE IF_P EXISTS qualified_name OptSeqOptList
+				USING access_method
+				{
+					AlterSeqStmt *n = makeNode(AlterSeqStmt);
+					n->sequence = $5;
+					n->accessMethod = $8;
+					n->options = $6;
+					n->amoptions = NIL;
+					n->missing_ok = true;
+					$$ = (Node *)n;
+				}
+			| ALTER SEQUENCE IF_P EXISTS qualified_name OptSeqOptList
+				USING access_method WITH reloptions
+				{
+					AlterSeqStmt *n = makeNode(AlterSeqStmt);
+					n->sequence = $5;
+					n->accessMethod = $8;
+					n->options = $6;
+					n->amoptions = $10;
 					n->missing_ok = true;
 					$$ = (Node *)n;
 				}
-
 		;
 
 OptSeqOptList: SeqOptList							{ $$ = $1; }
@@ -3596,7 +3670,7 @@ SeqOptElem: CACHE NumericOnly
 				{
 					$$ = makeDefElem("restart", (Node *)$3);
 				}
-		;
+			;
 
 opt_by:		BY				{}
 			| /* empty */	{}
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 7c1939f..5994d18 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -399,6 +399,7 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 		seqstmt = makeNode(CreateSeqStmt);
 		seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
 		seqstmt->options = NIL;
+		seqstmt->amoptions = NIL;
 
 		/*
 		 * If this is ALTER ADD COLUMN, make sure the sequence will be owned
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index eca3f97..0aa4cf2 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -1059,10 +1059,12 @@ IndexScanOK(CatCache *cache, ScanKey cur_skey)
 
 		case AMOID:
 		case AMNAME:
+		case SEQAMOID:
+		case SEQAMNAME:
 
 			/*
-			 * Always do heap scans in pg_am, because it's so small there's
-			 * not much point in an indexscan anyway.  We *must* do this when
+			 * Always do heap scans in pg_am and pg_seqam, because they are
+			 * too small to benefit from an indexscan.  We *must* do this when
 			 * initially building critical relcache entries, but we might as
 			 * well just always do it.
 			 */
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 79244e5..d003a28 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -51,6 +51,7 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
+#include "catalog/pg_seqam.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
@@ -266,6 +267,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 RelationInitSequenceAccessInfo(Relation relation);
 static void load_critical_index(Oid indexoid, Oid heapoid);
 static TupleDesc GetPgClassDescriptor(void);
 static TupleDesc GetPgIndexDescriptor(void);
@@ -1055,11 +1057,14 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	else
 		relation->rd_rsdesc = NULL;
 
-	/*
-	 * if it's an index, initialize index-related information
-	 */
-	if (OidIsValid(relation->rd_rel->relam))
+	/* if it's an index, initialize index-related information */
+	if (relation->rd_rel->relkind == RELKIND_INDEX &&
+		OidIsValid(relation->rd_rel->relam))
 		RelationInitIndexAccessInfo(relation);
+	/* same for sequences */
+	else if (relation->rd_rel->relkind == RELKIND_SEQUENCE &&
+			 OidIsValid(relation->rd_rel->relam))
+		RelationInitSequenceAccessInfo(relation);
 
 	/* extract reloptions if any */
 	RelationParseRelOptions(relation, pg_class_tuple);
@@ -1535,6 +1540,39 @@ LookupOpclassInfo(Oid operatorClassOid,
 	return opcentry;
 }
 
+/*
+ * Initialize sequence-access-method support data for an index relation
+ */
+static void
+RelationInitSequenceAccessInfo(Relation rel)
+{
+	HeapTuple		amtuple;
+	MemoryContext	indexcxt;
+	Form_pg_seqam	amform;
+
+	indexcxt = AllocSetContextCreate(CacheMemoryContext,
+									 RelationGetRelationName(rel),
+									 ALLOCSET_SMALL_MINSIZE,
+									 ALLOCSET_SMALL_INITSIZE,
+									 ALLOCSET_SMALL_MAXSIZE);
+	rel->rd_indexcxt = indexcxt;
+
+	rel->rd_aminfo = (RelationAmInfo *)
+		MemoryContextAllocZero(rel->rd_indexcxt,
+							   sizeof(RelationAmInfo));
+
+	/*
+	 * Make a copy of the pg_am entry for the sequence's access method
+	 */
+	amtuple = SearchSysCache1(SEQAMOID, ObjectIdGetDatum(rel->rd_rel->relam));
+	if (!HeapTupleIsValid(amtuple))
+		elog(ERROR, "cache lookup failed for access method %u",
+			 rel->rd_rel->relam);
+	amform = (Form_pg_seqam) MemoryContextAlloc(rel->rd_indexcxt, sizeof(*amform));
+	memcpy(amform, GETSTRUCT(amtuple), sizeof(*amform));
+	ReleaseSysCache(amtuple);
+	rel->rd_seqam = amform;
+}
 
 /*
  *		formrdesc
@@ -4792,6 +4830,22 @@ load_relcache_init_file(bool shared)
 			rel->rd_supportinfo = (FmgrInfo *)
 				MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
 		}
+		else if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+		{
+			MemoryContext indexcxt;
+			Assert(!rel->rd_isnailed);
+			Assert(false);
+
+			indexcxt = AllocSetContextCreate(CacheMemoryContext,
+											 RelationGetRelationName(rel),
+											 ALLOCSET_SMALL_MINSIZE,
+											 ALLOCSET_SMALL_INITSIZE,
+											 ALLOCSET_SMALL_MAXSIZE);
+			rel->rd_indexcxt = indexcxt;
+			/* set up zeroed fmgr-info vectors */
+			rel->rd_aminfo = (RelationAmInfo *)
+				MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));
+		}
 		else
 		{
 			/* Count nailed rels to ensure we have 'em all */
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 94d951c..66deaa6 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -54,6 +54,7 @@
 #include "catalog/pg_shdepend.h"
 #include "catalog/pg_shdescription.h"
 #include "catalog/pg_shseclabel.h"
+#include "catalog/pg_seqam.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_tablespace.h"
 #include "catalog/pg_ts_config.h"
@@ -631,6 +632,28 @@ static const struct cachedesc cacheinfo[] = {
 		},
 		8
 	},
+	{SeqAccessMethodRelationId,	/* SEQAMNAME */
+		SeqAmNameIndexId,
+		1,
+		{
+			Anum_pg_seqam_amname,
+			0,
+			0,
+			0
+		},
+		4
+	},
+	{SeqAccessMethodRelationId,	/* SEQAMOID */
+		SeqAmOidIndexId,
+		1,
+		{
+			ObjectIdAttributeNumber,
+			0,
+			0,
+			0
+		},
+		4
+	},
 	{StatisticRelationId,		/* STATRELATTINH */
 		StatisticRelidAttnumInhIndexId,
 		3,
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index b1bff7f..51c8982 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -28,6 +28,7 @@
 
 #include "access/commit_ts.h"
 #include "access/gin.h"
+#include "access/seqam.h"
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
@@ -2788,6 +2789,17 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"default_sequenceam", PGC_USERSET, CLIENT_CONN_STATEMENT,
+			gettext_noop("Sets the default sequence am for any new sequences."),
+			gettext_noop("An empty string selects the 'local' sequence am."),
+			GUC_IS_NAME | GUC_NOT_IN_SAMPLE
+		},
+		&default_seqam,
+		"",
+		check_default_seqam, NULL, NULL
+	},
+
+	{
 		{"temp_tablespaces", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Sets the tablespace(s) to use for temporary tables and sort files."),
 			NULL,
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 4175ddc..f4d10e0 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -14567,7 +14567,8 @@ dumpSequence(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
 			   *incby,
 			   *maxv = NULL,
 			   *minv = NULL,
-			   *cache;
+			   *cache,
+			   *amname = "local";
 	char		bufm[100],
 				bufx[100];
 	bool		cycled;
@@ -14637,15 +14638,41 @@ dumpSequence(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
 	}
 #endif
 
-	startv = PQgetvalue(res, 0, 1);
-	incby = PQgetvalue(res, 0, 2);
+	startv = pg_strdup(PQgetvalue(res, 0, 1));
+	incby = pg_strdup(PQgetvalue(res, 0, 2));
 	if (!PQgetisnull(res, 0, 3))
-		maxv = PQgetvalue(res, 0, 3);
+		maxv = pg_strdup(PQgetvalue(res, 0, 3));
 	if (!PQgetisnull(res, 0, 4))
-		minv = PQgetvalue(res, 0, 4);
-	cache = PQgetvalue(res, 0, 5);
+		minv = pg_strdup(PQgetvalue(res, 0, 4));
+	cache = pg_strdup(PQgetvalue(res, 0, 5));
 	cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
 
+	PQclear(res);
+
+	res = ExecuteSqlQuery(fout, "SELECT EXISTS(SELECT 1 "
+								"FROM pg_catalog.pg_class c, "
+								"pg_catalog.pg_namespace n "
+								"WHERE n.oid = c.relnamespace "
+								"AND nspname = 'pg_catalog'"
+								"AND c.relname = 'pg_seqam' "
+								"AND c.relkind = 'r');",
+						  PGRES_TUPLES_OK);
+	if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
+	{
+		PQclear(res);
+
+		printfPQExpBuffer(query, "SELECT a.seqamname\n"
+								 "FROM pg_catalog.pg_seqam a, pg_catalog.pg_class c\n"
+								 "WHERE c.relam = a.oid AND c.oid = %u",
+						  tbinfo->dobj.catId.oid);
+
+		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+		amname = pg_strdup(PQgetvalue(res, 0, 0));
+	}
+
+	PQclear(res);
+
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
 	 */
@@ -14687,6 +14714,7 @@ dumpSequence(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
 					  "    CACHE %s%s",
 					  cache, (cycled ? "\n    CYCLE" : ""));
 
+	appendPQExpBuffer(query, "\n    USING %s", fmtId(amname));
 	appendPQExpBufferStr(query, ";\n");
 
 	appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
@@ -14753,8 +14781,6 @@ dumpSequence(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
 				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
-	PQclear(res);
-
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
 	destroyPQExpBuffer(labelq);
@@ -14769,17 +14795,30 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 {
 	TableInfo  *tbinfo = tdinfo->tdtable;
 	PGresult   *res;
-	char	   *last;
-	bool		called;
+	char	   *state;
 	PQExpBuffer query = createPQExpBuffer();
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
 
-	appendPQExpBuffer(query,
-					  "SELECT last_value, is_called FROM %s",
-					  fmtId(tbinfo->dobj.name));
+	res = ExecuteSqlQuery(fout, "SELECT EXISTS(SELECT 1 "
+								"FROM pg_catalog.pg_proc p, "
+								"pg_catalog.pg_namespace n "
+								"WHERE n.oid = p.pronamespace "
+								"AND nspname = 'pg_catalog'"
+								"AND p.proname = 'pg_sequence_dump_state');",
+						  PGRES_TUPLES_OK);
+
+	if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
+		appendPQExpBuffer(query,
+						  "SELECT quote_literal(last_value::text || ', ' || is_called::text) FROM %s",
+						  fmtId(tbinfo->dobj.name));
+	else
+		appendPQExpBuffer(query,
+						  "SELECT quote_literal(pg_catalog.pg_sequence_dump_state(%s))",
+						  fmtId(tbinfo->dobj.name));
 
+	PQclear(res);
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
 	if (PQntuples(res) != 1)
@@ -14791,14 +14830,12 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 		exit_nicely(1);
 	}
 
-	last = PQgetvalue(res, 0, 0);
-	called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
+	state = PQgetvalue(res, 0, 0);
 
 	resetPQExpBuffer(query);
-	appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
+	appendPQExpBufferStr(query, "SELECT pg_catalog.pg_sequence_restore_state(");
 	appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
-	appendPQExpBuffer(query, ", %s, %s);\n",
-					  last, (called ? "true" : "false"));
+	appendPQExpBuffer(query, ", %s);\n", state);
 
 	ArchiveEntry(fout, nilCatalogId, createDumpId(),
 				 tbinfo->dobj.name,
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 5a9ceca..6dc428d 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1372,30 +1372,6 @@ describeOneTableDetails(const char *schemaname,
 	res = NULL;
 
 	/*
-	 * If it's a sequence, fetch its values and store into an array that will
-	 * be used later.
-	 */
-	if (tableinfo.relkind == 'S')
-	{
-		printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
-		/* must be separate because fmtId isn't reentrant */
-		appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
-
-		res = PSQLexec(buf.data);
-		if (!res)
-			goto error_return;
-
-		seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
-
-		for (i = 0; i < PQnfields(res); i++)
-			seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
-		seq_values[i] = NULL;
-
-		PQclear(res);
-		res = NULL;
-	}
-
-	/*
 	 * Get column info
 	 *
 	 * You need to modify value of "firstvcol" which will be defined below if
@@ -1439,6 +1415,14 @@ describeOneTableDetails(const char *schemaname,
 
 	appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
 	appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
+	/*
+	 * For sequence, fetch only the common column unless verbose was specified.
+	 * Note that this is change from pre9.5 versions.
+	 */
+	if (tableinfo.relkind == 'S' && !verbose)
+		appendPQExpBufferStr(&buf, " AND attname IN ('sequence_name', "
+							 "'start_value', 'increment_by', 'max_value', "
+							 "'min_value', 'cache_value', 'is_cycled')");
 	appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
 
 	res = PSQLexec(buf.data);
@@ -1446,6 +1430,39 @@ describeOneTableDetails(const char *schemaname,
 		goto error_return;
 	numrows = PQntuples(res);
 
+	/*
+	 * If it's a sequence, fetch its values and store into an array that will
+	 * be used later.
+	 */
+	if (tableinfo.relkind == 'S')
+	{
+		PGresult   *result;
+
+		/*
+		 * Use column names from the column info query, to automatically skip
+		 * unwanted columns.
+		 */
+		printfPQExpBuffer(&buf, "SELECT ");
+		for (i = 0; i < numrows; i++)
+			appendPQExpBuffer(&buf, i > 0 ? ", %s" : "%s", fmtId(PQgetvalue(res, i, 0)));
+		appendPQExpBuffer(&buf, " FROM %s",
+						  fmtId(schemaname));
+		/* must be separate because fmtId isn't reentrant */
+		appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+
+		result = PSQLexec(buf.data);
+		if (!result)
+			goto error_return;
+
+		seq_values = pg_malloc((PQnfields(result) + 1) * sizeof(*seq_values));
+
+		for (i = 0; i < PQnfields(result); i++)
+			seq_values[i] = pg_strdup(PQgetvalue(result, 0, i));
+		seq_values[i] = NULL;
+
+		PQclear(result);
+	}
+
 	/* Make title */
 	switch (tableinfo.relkind)
 	{
@@ -1757,6 +1774,29 @@ describeOneTableDetails(const char *schemaname,
 		/* Footer information about a sequence */
 		PGresult   *result = NULL;
 
+		/* Get the Access Method name for the sequence */
+		printfPQExpBuffer(&buf, "SELECT a.seqamname\n"
+								"FROM pg_catalog.pg_seqam a, pg_catalog.pg_class c\n"
+								"WHERE c.relam = a.oid AND c.oid = %s", oid);
+
+		result = PSQLexec(buf.data);
+
+		/*
+		 * If we get no rows back, don't show anything (obviously). We should
+		 * never get more than one row back, but if we do, just ignore it and
+		 * don't print anything.
+		 */
+		if (!result)
+			goto error_return;
+		else if (PQntuples(result) == 1)
+		{
+			printfPQExpBuffer(&buf, _("Access Method: %s"),
+							  PQgetvalue(result, 0, 0));
+			printTableAddFooter(&cont, buf.data);
+		}
+
+		PQclear(result);
+
 		/* Get the column that owns this sequence */
 		printfPQExpBuffer(&buf, "SELECT pg_catalog.quote_ident(nspname) || '.' ||"
 						  "\n   pg_catalog.quote_ident(relname) || '.' ||"
@@ -1774,6 +1814,8 @@ describeOneTableDetails(const char *schemaname,
 						  oid);
 
 		result = PSQLexec(buf.data);
+
+		/* Same logic as above, only print result when we get one row. */
 		if (!result)
 			goto error_return;
 		else if (PQntuples(result) == 1)
@@ -1783,11 +1825,6 @@ describeOneTableDetails(const char *schemaname,
 			printTableAddFooter(&cont, buf.data);
 		}
 
-		/*
-		 * If we get no rows back, don't show anything (obviously). We should
-		 * never get more than one row back, but if we do, just ignore it and
-		 * don't print anything.
-		 */
 		PQclear(result);
 	}
 	else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index a538830..bf4cafa 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -46,8 +46,9 @@ typedef enum relopt_kind
 	RELOPT_KIND_SPGIST = (1 << 8),
 	RELOPT_KIND_VIEW = (1 << 9),
 	RELOPT_KIND_BRIN = (1 << 10),
+	RELOPT_KIND_SEQUENCE = (1 << 11),
 	/* if you add a new kind, make sure you update "last_default" too */
-	RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_BRIN,
+	RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_SEQUENCE,
 	/* some compilers treat enums as signed ints, so we can't use 1 << 31 */
 	RELOPT_KIND_MAX = (1 << 30)
 } relopt_kind;
@@ -272,6 +273,8 @@ extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
 extern bytea *view_reloptions(Datum reloptions, bool validate);
 extern bytea *index_reloptions(RegProcedure amoptions, Datum reloptions,
 				 bool validate);
+extern bytea *sequence_reloptions(RegProcedure amoptions, Datum reloptions,
+				 bool validate);
 extern bytea *attribute_reloptions(Datum reloptions, bool validate);
 extern bytea *tablespace_reloptions(Datum reloptions, bool validate);
 
diff --git a/src/include/access/seqam.h b/src/include/access/seqam.h
new file mode 100644
index 0000000..c4f6f73
--- /dev/null
+++ b/src/include/access/seqam.h
@@ -0,0 +1,75 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqam.h
+ *	  Public header file for Sequence access method.
+ *
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/access/seqam.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SEQAM_H
+#define SEQAM_H
+
+#include "fmgr.h"
+
+#include "access/htup.h"
+#include "commands/sequence.h"
+#include "utils/relcache.h"
+#include "storage/buf.h"
+#include "storage/bufpage.h"
+
+
+struct SequenceHandle;
+typedef struct SequenceHandle SequenceHandle;
+
+typedef struct SeqAMColumnData
+{
+	char   *colname;
+	Oid		coltyp;
+	int32	coltypmod;
+	bool	colnotnull;
+} SeqAMColumnData;
+
+typedef SeqAMColumnData *SeqAMColumn;
+
+extern char *default_seqam;
+
+extern Oid GetDefaultSeqAM(void);
+
+extern List *seqam_extra_columns(Oid seqamid);
+extern void seqam_init(Oid seqamid, List *seqparams,
+					   List *reloptions, bool is_init,
+					   Datum *values, bool *nulls);
+extern int64 seqam_alloc(Relation seqrel, SequenceHandle *seqh,
+						 int64 nrequested, int64 *last);
+extern void seqam_setval(Relation seqrel, SequenceHandle *seqh,
+						 int64 new_value);
+extern char *seqam_dump_state(Relation seqrel, SequenceHandle *seqh);
+extern void seqam_restore_state(Relation seqrel, SequenceHandle *seqh, char *state);
+
+extern Oid get_seqam_oid(const char *sequencename, bool missing_ok);
+
+extern SequenceHandle *sequence_open(Oid seq_relid);
+extern void sequence_close(SequenceHandle *seqh);
+extern HeapTuple sequence_read_tuple(SequenceHandle *seqh);
+extern void sequence_save_tuple(SequenceHandle *seqh, HeapTuple newtup, bool do_wal);
+extern void sequence_release_tuple(SequenceHandle *seqh);
+extern bool sequence_needs_wal(SequenceHandle *seqh);
+
+extern int64 sequence_increment(Relation seqrel, int64 *value, int64 incnum,
+								int64 minv, int64 maxv, int64 incby,
+								bool is_cycled, bool report_errors);
+
+extern Datum seqam_local_extracols(PG_FUNCTION_ARGS);
+extern Datum seqam_local_reloptions(PG_FUNCTION_ARGS);
+extern Datum seqam_local_init(PG_FUNCTION_ARGS);
+extern Datum seqam_local_alloc(PG_FUNCTION_ARGS);
+extern Datum seqam_local_setval(PG_FUNCTION_ARGS);
+extern Datum seqam_local_dump(PG_FUNCTION_ARGS);
+extern Datum seqam_local_restore(PG_FUNCTION_ARGS);
+
+#endif   /* SEQAM_H */
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index bde1a84..2daffe4 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -206,6 +206,11 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index, 2692, on pg_rewrite using btree(oid o
 DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index, 2693, on pg_rewrite using btree(ev_class oid_ops, rulename name_ops));
 #define RewriteRelRulenameIndexId  2693
 
+DECLARE_UNIQUE_INDEX(pg_seqam_name_index, 6020, on pg_seqam using btree(seqamname name_ops));
+#define SeqAmNameIndexId  6020
+DECLARE_UNIQUE_INDEX(pg_seqam_oid_index, 6021, on pg_seqam using btree(oid oid_ops));
+#define SeqAmOidIndexId  6021
+
 DECLARE_INDEX(pg_shdepend_depender_index, 1232, on pg_shdepend using btree(dbid oid_ops, classid oid_ops, objid oid_ops, objsubid int4_ops));
 #define SharedDependDependerIndexId		1232
 DECLARE_INDEX(pg_shdepend_reference_index, 1233, on pg_shdepend using btree(refclassid oid_ops, refobjid oid_ops));
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 910cfc6..a96347f 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1814,10 +1814,12 @@ DATA(insert OID = 1575 (  currval			PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 20
 DESCR("sequence current value");
 DATA(insert OID = 1576 (  setval			PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 20 "2205 20" _null_ _null_ _null_ _null_  setval_oid _null_ _null_ _null_ ));
 DESCR("set sequence value");
-DATA(insert OID = 1765 (  setval			PGNSP PGUID 12 1 0 0 0 f f f f t f v 3 0 20 "2205 20 16" _null_ _null_ _null_ _null_ setval3_oid _null_ _null_ _null_ ));
-DESCR("set sequence value and is_called status");
 DATA(insert OID = 3078 (  pg_sequence_parameters	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2249 "26" "{26,20,20,20,20,16}" "{i,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option}" _null_ pg_sequence_parameters _null_ _null_ _null_));
 DESCR("sequence parameters, for use by information schema");
+DATA(insert OID = 3261 (  pg_sequence_dump_state	PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2275 "2205" _null_ _null_ _null_ _null_	pg_sequence_dump_state _null_ _null_ _null_ ));
+DESCR("Dump state of a sequence");
+DATA(insert OID = 3262 (  pg_sequence_restore_state	   PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 2278 "2205 2275" _null_ _null_ _null_ _null_	pg_sequence_restore_state _null_ _null_ _null_ ));
+DESCR("Restore state of a sequence");
 
 DATA(insert OID = 1579 (  varbit_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -5042,6 +5044,22 @@ DESCR("peek at changes from replication slot");
 DATA(insert OID = 3785 (  pg_logical_slot_peek_binary_changes PGNSP PGUID 12 1000 1000 25 0 f f f f f t v 4 0 2249 "19 3220 23 1009" "{19,3220,23,1009,3220,28,17}" "{i,i,i,v,o,o,o}" "{slot_name,upto_lsn,upto_nchanges,options,location,xid,data}" _null_ pg_logical_slot_peek_binary_changes _null_ _null_ _null_ ));
 DESCR("peek at binary changes from replication slot");
 
+DATA(insert OID = 6022 (  seqam_local_extracols	   PGNSP PGUID 12 1 0 0 0 f f f f f f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ seqam_local_extracols _null_ _null_ _null_ ));
+DESCR("Get local SequenceAM extra columns");
+DATA(insert OID = 6023 (  seqam_local_reloptions	   PGNSP PGUID 12 1 0 0 0 f f f f f f s 2 0 2281 "2281 16" _null_ _null_ _null_ _null_ seqam_local_reloptions _null_ _null_ _null_ ));
+DESCR("Local SequenceAM options");
+DATA(insert OID = 6024 (  seqam_local_init	   PGNSP PGUID 12 1 0 0 0 f f f f f f s 5 0 2278 "2281 17 16 2281 2281" _null_ _null_ _null_ _null_ seqam_local_init _null_ _null_ _null_ ));
+DESCR("Initialize local SequenceAM sequence");
+DATA(insert OID = 6025 (  seqam_local_alloc	   PGNSP PGUID 12 1 0 0 0 f f f f f f v 4 0 2281 "2281 2281 20 2281" _null_ _null_ _null_ _null_ seqam_local_alloc _null_ _null_ _null_ ));
+DESCR("Local SequenceAM allocation");
+DATA(insert OID = 6026 (  seqam_local_setval	   PGNSP PGUID 12 1 0 0 0 f f f f f f s 3 0 2278 "2281 2281 20" _null_ _null_ _null_ _null_ seqam_local_setval _null_ _null_ _null_ ));
+DESCR("Set value of a local SequenceAM sequence");
+DATA(insert OID = 6027 (  seqam_local_dump	   PGNSP PGUID 12 1 0 0 0 f f f f f f s 2 0 17 "2281 2281" _null_ _null_ _null_ _null_ seqam_local_dump _null_ _null_ _null_ ));
+DESCR("Dump state of a local SequenceAM sequence");
+DATA(insert OID = 6028 (  seqam_local_restore	   PGNSP PGUID 12 1 0 0 0 f f f f f f s 3 0 2278 "2281 2281 17" _null_ _null_ _null_ _null_ seqam_local_restore _null_ _null_ _null_ ));
+DESCR("Restore state of a local SequenceAM sequence");
+
+
 /* event triggers */
 DATA(insert OID = 3566 (  pg_event_trigger_dropped_objects		PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25}" "{o,o,o,o,o,o,o}" "{classid, objid, objsubid, object_type, schema_name, object_name, object_identity}" _null_ pg_event_trigger_dropped_objects _null_ _null_ _null_ ));
 DESCR("list objects dropped by the current command");
diff --git a/src/include/catalog/pg_seqam.h b/src/include/catalog/pg_seqam.h
new file mode 100644
index 0000000..e08c935
--- /dev/null
+++ b/src/include/catalog/pg_seqam.h
@@ -0,0 +1,78 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_seqam.h
+ *	  definition of the system "sequence access method" relation (pg_seqam)
+ *	  along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/catalog/pg_seqam.h
+ *
+ * NOTES
+ *		the genbki.pl script reads this file and generates .bki
+ *		information from the DATA() statements.
+ *
+ *		XXX do NOT break up DATA() statements into multiple lines!
+ *			the scripts are not as smart as you might think...
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_SEQAM_H
+#define PG_SEQAM_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ *		pg_seqam definition.  cpp turns this into
+ *		typedef struct FormData_pg_seqam
+ * ----------------
+ */
+#define SeqAccessMethodRelationId	32
+
+CATALOG(pg_seqam,32)
+{
+	NameData	seqamname;			/* access method name */
+	regproc		seqamextracols;		/* get extra columns this am stores in the sequence relation */
+	regproc		seqamreloptions;	/* parse AM-specific options */
+	regproc		seqaminit;			/* sequence initialization */
+	regproc		seqamalloc;			/* get next allocation of range of values function */
+	regproc		seqamsetval;		/* set value function */
+	regproc		seqamdump;			/* dump state, used by pg_dump */
+	regproc		seqamrestore;		/* restore state, used when loading pg_dump */
+} FormData_pg_seqam;
+
+/* ----------------
+ *		Form_pg_seqam corresponds to a pointer to a tuple with
+ *		the format of pg_seqam relation.
+ * ----------------
+ */
+typedef FormData_pg_seqam *Form_pg_seqam;
+
+/* ----------------
+ *		compiler constants for pg_seqam
+ * ----------------
+ */
+#define Natts_pg_seqam						8
+#define Anum_pg_seqam_amname				1
+#define Anum_pg_seqam_amextracols			2
+#define Anum_pg_seqam_amreloptions			3
+#define Anum_pg_seqam_aminit				4
+#define Anum_pg_seqam_amalloc				5
+#define Anum_pg_seqam_amsetval				6
+#define Anum_pg_seqam_amdump				7
+#define Anum_pg_seqam_amrestore				8
+
+/* ----------------
+ *		initial contents of pg_seqam
+ * ----------------
+ */
+
+DATA(insert OID = 2 (  local		seqam_local_extracols seqam_local_reloptions seqam_local_init seqam_local_alloc seqam_local_setval seqam_local_dump seqam_local_restore));
+DESCR("local sequence access method");
+#define LOCAL_SEQAM_OID 2
+
+#define DEFAULT_SEQAM	""
+
+#endif   /* PG_SEQAM_H */
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 386f1e6..8688620 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -23,15 +23,12 @@
 typedef struct FormData_pg_sequence
 {
 	NameData	sequence_name;
-	int64		last_value;
 	int64		start_value;
 	int64		increment_by;
 	int64		max_value;
 	int64		min_value;
 	int64		cache_value;
-	int64		log_cnt;
 	bool		is_cycled;
-	bool		is_called;
 } FormData_pg_sequence;
 
 typedef FormData_pg_sequence *Form_pg_sequence;
@@ -41,18 +38,14 @@ typedef FormData_pg_sequence *Form_pg_sequence;
  */
 
 #define SEQ_COL_NAME			1
-#define SEQ_COL_LASTVAL			2
-#define SEQ_COL_STARTVAL		3
-#define SEQ_COL_INCBY			4
-#define SEQ_COL_MAXVALUE		5
-#define SEQ_COL_MINVALUE		6
-#define SEQ_COL_CACHE			7
-#define SEQ_COL_LOG				8
-#define SEQ_COL_CYCLE			9
-#define SEQ_COL_CALLED			10
-
+#define SEQ_COL_STARTVAL		2
+#define SEQ_COL_INCBY			3
+#define SEQ_COL_MAXVALUE		4
+#define SEQ_COL_MINVALUE		5
+#define SEQ_COL_CACHE			6
+#define SEQ_COL_CYCLE			7
 #define SEQ_COL_FIRSTCOL		SEQ_COL_NAME
-#define SEQ_COL_LASTCOL			SEQ_COL_CALLED
+#define SEQ_COL_LASTCOL			SEQ_COL_CYCLE
 
 /* XLOG stuff */
 #define XLOG_SEQ_LOG			0x00
@@ -67,10 +60,11 @@ extern Datum nextval(PG_FUNCTION_ARGS);
 extern Datum nextval_oid(PG_FUNCTION_ARGS);
 extern Datum currval_oid(PG_FUNCTION_ARGS);
 extern Datum setval_oid(PG_FUNCTION_ARGS);
-extern Datum setval3_oid(PG_FUNCTION_ARGS);
 extern Datum lastval(PG_FUNCTION_ARGS);
 
 extern Datum pg_sequence_parameters(PG_FUNCTION_ARGS);
+extern Datum pg_sequence_dump_state(PG_FUNCTION_ARGS);
+extern Datum pg_sequence_restore_state(PG_FUNCTION_ARGS);
 
 extern Oid	DefineSequence(CreateSeqStmt *stmt);
 extern Oid	AlterSequence(AlterSeqStmt *stmt);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5eaa435..fb355dc 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1283,6 +1283,7 @@ typedef enum AlterTableType
 	AT_AddColumn,				/* add column */
 	AT_AddColumnRecurse,		/* internal to commands/tablecmds.c */
 	AT_AddColumnToView,			/* implicitly via CREATE OR REPLACE VIEW */
+	AT_AddColumnToSequence,		/* implicitly via ALTER SEQUENCE USING */
 	AT_ColumnDefault,			/* alter column default */
 	AT_DropNotNull,				/* alter column drop not null */
 	AT_SetNotNull,				/* alter column set not null */
@@ -1292,6 +1293,7 @@ typedef enum AlterTableType
 	AT_SetStorage,				/* alter column set storage */
 	AT_DropColumn,				/* drop column */
 	AT_DropColumnRecurse,		/* internal to commands/tablecmds.c */
+	AT_DropColumnFromSequence,	/* implicitly via ALTER SEQUENCE USING */
 	AT_AddIndex,				/* add index */
 	AT_ReAddIndex,				/* internal to commands/tablecmds.c */
 	AT_AddConstraint,			/* add constraint */
@@ -2011,8 +2013,10 @@ typedef struct CreateSeqStmt
 {
 	NodeTag		type;
 	RangeVar   *sequence;		/* the sequence to create */
-	List	   *options;
+	List       *options;        /* standard sequence options */
+	List	   *amoptions;		/* am specific options */
 	Oid			ownerId;		/* ID of owner, or InvalidOid for default */
+	char       *accessMethod;   /* USING name of access method (eg. Local) */
 	bool		if_not_exists;	/* just do nothing if it already exists? */
 } CreateSeqStmt;
 
@@ -2020,8 +2024,10 @@ typedef struct AlterSeqStmt
 {
 	NodeTag		type;
 	RangeVar   *sequence;		/* the sequence to alter */
-	List	   *options;
+	List       *options;        /* standard sequence options */
+	List	   *amoptions;		/* am specific options */
 	bool		missing_ok;		/* skip error if a role is missing? */
+	char       *accessMethod;   /* USING name of access method (eg. Local) */
 } AlterSeqStmt;
 
 /* ----------------------
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 80813d2..507044e 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -404,6 +404,7 @@ extern void GUC_check_errcode(int sqlerrcode);
  */
 
 /* in commands/tablespace.c */
+extern bool check_default_seqam(char **newval, void **extra, GucSource source);
 extern bool check_default_tablespace(char **newval, void **extra, GucSource source);
 extern bool check_temp_tablespaces(char **newval, void **extra, GucSource source);
 extern void assign_temp_tablespaces(const char *newval, void *extra);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 48ebf59..2998688 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -18,6 +18,7 @@
 #include "catalog/pg_am.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_index.h"
+#include "catalog/pg_seqam.h"
 #include "fmgr.h"
 #include "nodes/bitmapset.h"
 #include "rewrite/prs2lock.h"
@@ -48,10 +49,12 @@ typedef LockInfoData *LockInfo;
 
 /*
  * Cached lookup information for the frequently used index access method
- * functions, defined by the pg_am row associated with an index relation.
+ * functions, defined by the pg_am row associated with an index relation, or the pg_seqam
+ * row associated with a sequence relation.
  */
 typedef struct RelationAmInfo
 {
+	/* pg_am only */
 	FmgrInfo	aminsert;
 	FmgrInfo	ambeginscan;
 	FmgrInfo	amgettuple;
@@ -61,6 +64,14 @@ typedef struct RelationAmInfo
 	FmgrInfo	ammarkpos;
 	FmgrInfo	amrestrpos;
 	FmgrInfo	amcanreturn;
+	FmgrInfo	amcostestimate;
+
+	/* pg_seqam only */
+	FmgrInfo	seqamalloc;
+	FmgrInfo	seqamsetval;
+
+	/* Common */
+	FmgrInfo	amoptions;
 } RelationAmInfo;
 
 
@@ -131,23 +142,25 @@ typedef struct RelationData
 	struct HeapTupleData *rd_indextuple;		/* all of pg_index tuple */
 	Form_pg_am	rd_am;			/* pg_am tuple for index's AM */
 
+	Form_pg_seqam rd_seqam;		/* pg_seqam tuple for sequence's AM */
+
 	/*
-	 * index access support info (used only for an index relation)
+	 * Access support info (used only for index or sequence relations)
 	 *
 	 * Note: only default support procs for each opclass are cached, namely
 	 * those with lefttype and righttype equal to the opclass's opcintype. The
 	 * arrays are indexed by support function number, which is a sufficient
 	 * identifier given that restriction.
 	 *
-	 * Note: rd_amcache is available for index AMs to cache private data about
-	 * an index.  This must be just a cache since it may get reset at any time
+	 * Note: rd_amcache is available for AMs to cache private data about
+	 * an object.  This must be just a cache since it may get reset at any time
 	 * (in particular, it will get reset by a relcache inval message for the
 	 * index).  If used, it must point to a single memory chunk palloc'd in
 	 * rd_indexcxt.  A relcache reset will include freeing that chunk and
 	 * setting rd_amcache = NULL.
 	 */
 	MemoryContext rd_indexcxt;	/* private memory cxt for this stuff */
-	RelationAmInfo *rd_aminfo;	/* lookup info for funcs found in pg_am */
+	RelationAmInfo *rd_aminfo;	/* lookup info for funcs found in pg_am or pg_seqam */
 	Oid		   *rd_opfamily;	/* OIDs of op families for each index col */
 	Oid		   *rd_opcintype;	/* OIDs of opclass declared input data types */
 	RegProcedure *rd_support;	/* OIDs of support procedures */
@@ -158,7 +171,7 @@ typedef struct RelationData
 	Oid		   *rd_exclops;		/* OIDs of exclusion operators, if any */
 	Oid		   *rd_exclprocs;	/* OIDs of exclusion ops' procs, if any */
 	uint16	   *rd_exclstrats;	/* exclusion ops' strategy numbers, if any */
-	void	   *rd_amcache;		/* available for use by index AM */
+	void	   *rd_amcache;		/* available for use by AM */
 	Oid		   *rd_indcollation;	/* OIDs of index collations */
 
 	/*
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
index f97229f..2810a8d 100644
--- a/src/include/utils/syscache.h
+++ b/src/include/utils/syscache.h
@@ -78,6 +78,8 @@ enum SysCacheIdentifier
 	RELNAMENSP,
 	RELOID,
 	RULERELNAME,
+	SEQAMNAME,
+	SEQAMOID,
 	STATRELATTINH,
 	TABLESPACEOID,
 	TSCONFIGMAP,
diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out
index 7991e99..6b6493e 100644
--- a/src/test/regress/expected/rangefuncs.out
+++ b/src/test/regress/expected/rangefuncs.out
@@ -719,10 +719,10 @@ CREATE FUNCTION foo_mat(int,int) RETURNS setof foo_rescan_t AS 'begin for i in $
 --invokes ExecReScanFunctionScan - all these cases should materialize the function only once
 -- LEFT JOIN on a condition that the planner can't prove to be true is used to ensure the function
 -- is on the inner path of a nestloop join
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_sql(11,13) ON (r+i)<100;
@@ -739,10 +739,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_sql(11,13) ON (r+i)<100;
  3 | 13 | 3
 (9 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_sql(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100;
@@ -759,10 +759,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_sql(11,13) WITH ORDINALITY
  3 | 13 | 3 | 3
 (9 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_mat(11,13) ON (r+i)<100;
@@ -779,10 +779,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_mat(11,13) ON (r+i)<100;
  3 | 13 | 3
 (9 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_mat(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100;
@@ -799,10 +799,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_mat(11,13) WITH ORDINALITY
  3 | 13 | 3 | 3
 (9 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN ROWS FROM( foo_sql(11,13), foo_mat(11,13) ) WITH ORDINALITY AS f(i1,s1,i2,s2,o) ON (r+i1+i2)<100;
@@ -876,10 +876,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN unnest(array[10,20,30]) WITH O
 (9 rows)
 
 --invokes ExecReScanFunctionScan with chgParam != NULL (using implied LATERAL)
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(10+r,13);
@@ -893,10 +893,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(10+r,13);
  3 | 13 | 6
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(10+r,13) WITH ORDINALITY AS f(i,s,o);
@@ -910,10 +910,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(10+r,13) WITH ORDINALITY AS f(i
  3 | 13 | 6 | 1
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(11,10+r);
@@ -927,10 +927,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(11,10+r);
  3 | 13 | 6
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(11,10+r) WITH ORDINALITY AS f(i,s,o);
@@ -944,10 +944,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(11,10+r) WITH ORDINALITY AS f(i
  3 | 13 | 6 | 3
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_sql(r1,r2);
@@ -965,10 +965,10 @@ SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_sql(r1,r2);
  16 | 20 | 20 | 10
 (10 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_sql(r1,r2) WITH ORDINALITY AS f(i,s,o);
@@ -986,10 +986,10 @@ SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_sql(r1,r2) WITH ORD
  16 | 20 | 20 | 10 | 5
 (10 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(10+r,13);
@@ -1003,10 +1003,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(10+r,13);
  3 | 13 | 6
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(10+r,13) WITH ORDINALITY AS f(i,s,o);
@@ -1020,10 +1020,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(10+r,13) WITH ORDINALITY AS f(i
  3 | 13 | 6 | 1
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(11,10+r);
@@ -1037,10 +1037,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(11,10+r);
  3 | 13 | 6
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(11,10+r) WITH ORDINALITY AS f(i,s,o);
@@ -1054,10 +1054,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(11,10+r) WITH ORDINALITY AS f(i
  3 | 13 | 6 | 3
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_mat(r1,r2);
@@ -1075,10 +1075,10 @@ SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_mat(r1,r2);
  16 | 20 | 20 | 10
 (10 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_mat(r1,r2) WITH ORDINALITY AS f(i,s,o);
@@ -1097,10 +1097,10 @@ SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_mat(r1,r2) WITH ORD
 (10 rows)
 
 -- selective rescan of multiple functions:
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(11,11), foo_mat(10+r,13) );
@@ -1114,10 +1114,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(11,11), foo_mat(10+r
  3 | 11 | 1 | 13 | 6
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(10+r,13), foo_mat(11,11) );
@@ -1131,10 +1131,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(10+r,13), foo_mat(11
  3 | 13 | 6 | 11 | 1
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(10+r,13), foo_mat(10+r,13) );
@@ -1148,10 +1148,10 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(10+r,13), foo_mat(10
  3 | 13 | 6 | 13 | 6
 (6 rows)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
- setval | setval 
---------+--------
-      1 |      1
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
+ pg_sequence_restore_state | pg_sequence_restore_state 
+---------------------------+---------------------------
+                           | 
 (1 row)
 
 SELECT * FROM generate_series(1,2) r1, generate_series(r1,3) r2, ROWS FROM( foo_sql(10+r1,13), foo_mat(10+r2,13) );
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index c7be273..d4e250f 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -123,6 +123,7 @@ pg_proc|t
 pg_range|t
 pg_rewrite|t
 pg_seclabel|t
+pg_seqam|t
 pg_shdepend|t
 pg_shdescription|t
 pg_shseclabel|t
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 8783ca6..ea45a2d 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -129,10 +129,10 @@ SELECT nextval('sequence_test'::regclass);
       33
 (1 row)
 
-SELECT setval('sequence_test'::text, 99, false);
- setval 
---------
-     99
+SELECT pg_sequence_restore_state('sequence_test'::text, '99, false');
+ pg_sequence_restore_state 
+---------------------------
+ 
 (1 row)
 
 SELECT nextval('sequence_test'::regclass);
@@ -153,10 +153,10 @@ SELECT nextval('sequence_test'::text);
       33
 (1 row)
 
-SELECT setval('sequence_test'::regclass, 99, false);
- setval 
---------
-     99
+SELECT pg_sequence_restore_state('sequence_test'::regclass, '99, false');
+ pg_sequence_restore_state 
+---------------------------
+ 
 (1 row)
 
 SELECT nextval('sequence_test'::text);
@@ -173,9 +173,9 @@ DROP SEQUENCE sequence_test;
 CREATE SEQUENCE foo_seq;
 ALTER TABLE foo_seq RENAME TO foo_seq_new;
 SELECT * FROM foo_seq_new;
- sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
- foo_seq       |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | f
+ sequence_name | start_value | increment_by |      max_value      | min_value | cache_value | is_cycled | last_value | log_cnt | is_called 
+---------------+-------------+--------------+---------------------+-----------+-------------+-----------+------------+---------+-----------
+ foo_seq       |           1 |            1 | 9223372036854775807 |         1 |           1 | f         |          1 |       0 | f
 (1 row)
 
 SELECT nextval('foo_seq_new');
@@ -191,9 +191,9 @@ SELECT nextval('foo_seq_new');
 (1 row)
 
 SELECT * FROM foo_seq_new;
- sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
- foo_seq       |          2 |           1 |            1 | 9223372036854775807 |         1 |           1 |      31 | f         | t
+ sequence_name | start_value | increment_by |      max_value      | min_value | cache_value | is_cycled | last_value | log_cnt | is_called 
+---------------+-------------+--------------+---------------------+-----------+-------------+-----------+------------+---------+-----------
+ foo_seq       |           1 |            1 | 9223372036854775807 |         1 |           1 | f         |          2 |      31 | t
 (1 row)
 
 DROP SEQUENCE foo_seq_new;
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 80c5706..d1bc3d7 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -100,14 +100,14 @@ SELECT table_name, column_name, is_updatable
  ro_view17  | b             | NO
  ro_view18  | a             | NO
  ro_view19  | sequence_name | NO
- ro_view19  | last_value    | NO
  ro_view19  | start_value   | NO
  ro_view19  | increment_by  | NO
  ro_view19  | max_value     | NO
  ro_view19  | min_value     | NO
  ro_view19  | cache_value   | NO
- ro_view19  | log_cnt       | NO
  ro_view19  | is_cycled     | NO
+ ro_view19  | last_value    | NO
+ ro_view19  | log_cnt       | NO
  ro_view19  | is_called     | NO
  ro_view2   | a             | NO
  ro_view2   | b             | NO
diff --git a/src/test/regress/sql/rangefuncs.sql b/src/test/regress/sql/rangefuncs.sql
index 470571b..b97670f 100644
--- a/src/test/regress/sql/rangefuncs.sql
+++ b/src/test/regress/sql/rangefuncs.sql
@@ -242,16 +242,16 @@ CREATE FUNCTION foo_mat(int,int) RETURNS setof foo_rescan_t AS 'begin for i in $
 -- LEFT JOIN on a condition that the planner can't prove to be true is used to ensure the function
 -- is on the inner path of a nestloop join
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_sql(11,13) ON (r+i)<100;
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_sql(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100;
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_mat(11,13) ON (r+i)<100;
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN foo_mat(11,13) WITH ORDINALITY AS f(i,s,o) ON (r+i)<100;
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN ROWS FROM( foo_sql(11,13), foo_mat(11,13) ) WITH ORDINALITY AS f(i1,s1,i2,s2,o) ON (r+i1+i2)<100;
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN generate_series(11,13) f(i) ON (r+i)<100;
@@ -262,42 +262,42 @@ SELECT * FROM (VALUES (1),(2),(3)) v(r) LEFT JOIN unnest(array[10,20,30]) WITH O
 
 --invokes ExecReScanFunctionScan with chgParam != NULL (using implied LATERAL)
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(10+r,13);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(10+r,13) WITH ORDINALITY AS f(i,s,o);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(11,10+r);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_sql(11,10+r) WITH ORDINALITY AS f(i,s,o);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_sql(r1,r2);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_sql(r1,r2) WITH ORDINALITY AS f(i,s,o);
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(10+r,13);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(10+r,13) WITH ORDINALITY AS f(i,s,o);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(11,10+r);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), foo_mat(11,10+r) WITH ORDINALITY AS f(i,s,o);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_mat(r1,r2);
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (11,12),(13,15),(16,20)) v(r1,r2), foo_mat(r1,r2) WITH ORDINALITY AS f(i,s,o);
 
 -- selective rescan of multiple functions:
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(11,11), foo_mat(10+r,13) );
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(10+r,13), foo_mat(11,11) );
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM (VALUES (1),(2),(3)) v(r), ROWS FROM( foo_sql(10+r,13), foo_mat(10+r,13) );
 
-SELECT setval('foo_rescan_seq1',1,false),setval('foo_rescan_seq2',1,false);
+SELECT pg_sequence_restore_state('foo_rescan_seq1','1,false'),pg_sequence_restore_state('foo_rescan_seq2','1,false');
 SELECT * FROM generate_series(1,2) r1, generate_series(r1,3) r2, ROWS FROM( foo_sql(10+r1,13), foo_mat(10+r2,13) );
 
 SELECT * FROM (VALUES (1),(2),(3)) v(r), generate_series(10+r,20-r) f(i);
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index 0dd653d..aa60bfd 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -67,11 +67,11 @@ SELECT currval('sequence_test'::text);
 SELECT currval('sequence_test'::regclass);
 SELECT setval('sequence_test'::text, 32);
 SELECT nextval('sequence_test'::regclass);
-SELECT setval('sequence_test'::text, 99, false);
+SELECT pg_sequence_restore_state('sequence_test'::text, '99, false');
 SELECT nextval('sequence_test'::regclass);
 SELECT setval('sequence_test'::regclass, 32);
 SELECT nextval('sequence_test'::text);
-SELECT setval('sequence_test'::regclass, 99, false);
+SELECT pg_sequence_restore_state('sequence_test'::regclass, '99, false');
 SELECT nextval('sequence_test'::text);
 DISCARD SEQUENCES;
 SELECT currval('sequence_test'::regclass);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to