Hi,

I rewrote the patch with different API along the lines of what was discussed.

The API now consists of following functions:
sequence_alloc - allocating range of new values
The function receives the sequence relation, current value, number of requested values amdata and relevant sequence options like min/max and returns new amdata, new current value, number of values allocated and also if it needs wal write (that should be returned if amdata has changed plus other reasons the AM might have to force the wal update).

sequence_setval - notification that setval is happening
This function gets sequence relation, previous value and new value plus the amdata and returns amdata (I can imagine some complex sequence AMs will want to throw error that setval can't be done on them).

sequence_request_update/sequence_update - used for background processing
Basically AM can call the sequence_request_update and backend will then call the sequence_update method of an AM with current amdata and will write the updated amdata to disk

sequence_seqparams - function to process/validate the standard sequence options like start position, min/max, increment by etc by the AM, it's called in addition to the standard processing

sequence_reloptions - this is the only thing that remained unchanged from previous patch, it's meant to pass custom options to the AM

Only the alloc and reloptions methods are required (and implemented by the local AM).

The caching, xlog writing, updating the page, etc is handled by backend, the AM does not see the tuple at all. I decided to not pass even the struct around and just pass the relevant options because I think if we want to abstract the storage properly then the AM should not care about how the pg_sequence looks like at all, even if it means that the sequence_alloc parameter list is bit long.

For the amdata handling (which is the AM's private data variable) the API assumes that (Datum) 0 is NULL, this seems to work well for reloptions so should work here also and it simplifies things a little compared to passing pointers to pointers around and making sure everything is allocated, etc.

Sadly the fact that amdata is not fixed size and can be NULL made the page updates of the sequence relation quite more complex that it used to be. There are probably some optimizations possible there but I think the patch is good enough for the review now, so I am adding it to October commitfest.

--
 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 c32088f..aea4a14 100644
--- a/src/backend/access/Makefile
+++ b/src/backend/access/Makefile
@@ -8,6 +8,6 @@ subdir = src/backend/access
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS	    = common gin gist hash heap index nbtree rmgrdesc spgist transam
+SUBDIRS	    = 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 e0b81b9..c5b7e0a 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -306,6 +306,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
@@ -806,7 +807,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)
@@ -839,6 +841,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;
@@ -1284,13 +1289,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..f782f7e
--- /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
+
+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..552225a
--- /dev/null
+++ b/src/backend/access/sequence/seqam.c
@@ -0,0 +1,351 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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 = &seqRelation->rd_aminfo->pname; \
+	if (!OidIsValid(procedure->fn_oid)) \
+	{ \
+		RegProcedure	procOid = seqRelation->rd_seqam->pname; \
+		if (RegProcedureIsValid(procOid)) \
+			fmgr_info_cxt(procOid, procedure, seqRelation->rd_indexcxt); \
+		else if (!missing_ok) \
+			elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
+	} \
+} while(0)
+
+/*-------------------------------------------------------------------------
+ *
+ *  Sequence Access Manager API
+ *
+ *  INTERFACE ROUTINES
+ *		sequence_alloc		- allocate a new range of values for the sequence
+ *		sequence_setval		- coordinate the reset of a sequence to new value
+ *		sequence_update		- callback for background processing (called
+ *		                      by sequence_request_update)
+ *		sequence_seqparams	- process the standard sequence parameters
+ *
+ *		sequence_reloptions	- process reloptions - located in reloptions.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * sequence_alloc - allocate sequence values in a sequence
+ */
+Datum
+sequence_alloc(Relation seqRelation, int64 *current_value, int64 nrequested,
+			   int64 min_value, int64 max_value, int64 increment_by,
+			   bool is_cycled, Datum amdata, int64 *nallocated,
+			   bool *xlog_needed)
+{
+	FmgrInfo   *procedure;
+	FunctionCallInfoData fcinfo;
+
+	Assert(RelationIsValid(seqRelation));
+	Assert(PointerIsValid(seqRelation->rd_seqam));
+	Assert(OidIsValid(seqRelation->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamalloc, false);
+
+	/*
+	 * have the seqam's alloc proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, procedure, 10, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqRelation);
+	fcinfo.arg[1] = PointerGetDatum(current_value);
+	fcinfo.arg[2] = Int64GetDatum(nrequested);
+	fcinfo.arg[3] = Int64GetDatum(min_value);
+	fcinfo.arg[4] = Int64GetDatum(max_value);
+	fcinfo.arg[5] = Int64GetDatum(increment_by);
+	fcinfo.arg[6] = BoolGetDatum(is_cycled);
+	fcinfo.arg[7] = amdata;
+	fcinfo.arg[8] = PointerGetDatum(nallocated);
+	fcinfo.arg[9] = PointerGetDatum(xlog_needed);
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+	fcinfo.argnull[2] = false;
+	fcinfo.argnull[3] = false;
+	fcinfo.argnull[4] = false;
+	fcinfo.argnull[5] = false;
+	fcinfo.argnull[6] = false;
+	fcinfo.argnull[7] = false;
+	fcinfo.argnull[8] = false;
+	fcinfo.argnull[9] = false;
+
+	return FunctionCallInvoke(&fcinfo);
+}
+
+/*
+ * sequence_setval - set sequence values in a sequence
+ */
+Datum
+sequence_setval(Relation seqRelation, int64 current_value, int64 new_value,
+				Datum amdata)
+{
+	FmgrInfo   *procedure;
+	FunctionCallInfoData fcinfo;
+
+	Assert(RelationIsValid(seqRelation));
+	Assert(PointerIsValid(seqRelation->rd_seqam));
+	Assert(OidIsValid(seqRelation->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamsetval, true);
+
+	if (!OidIsValid(procedure->fn_oid))
+		return amdata;
+
+	/*
+	 * have the seqam's setval proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, procedure, 4, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqRelation);
+	fcinfo.arg[1] = Int64GetDatum(current_value);
+	fcinfo.arg[2] = Int64GetDatum(new_value);
+	fcinfo.arg[3] = amdata;
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+	fcinfo.argnull[2] = false;
+	fcinfo.argnull[3] = false;
+
+	return FunctionCallInvoke(&fcinfo);
+}
+
+/*
+ * sequence_update - callback for sequence_request_update
+ */
+Datum
+sequence_update(Relation seqRelation, Datum amdata)
+{
+	FmgrInfo   *procedure;
+	FunctionCallInfoData fcinfo;
+
+	Assert(RelationIsValid(seqRelation));
+	Assert(PointerIsValid(seqRelation->rd_seqam));
+	Assert(OidIsValid(seqRelation->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamupdate, true);
+
+	if (!OidIsValid(procedure->fn_oid))
+		return amdata;
+
+	/*
+	 * have the seqam's update proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, procedure, 2, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(seqRelation);
+	fcinfo.arg[1] = amdata;
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+
+	return FunctionCallInvoke(&fcinfo);
+}
+
+/*
+ * sequence_seqparams - process standard sequence params
+ */
+Datum
+sequence_seqparams(RegProcedure amoptions, List *params, Datum amdata,
+				   bool isInit)
+{
+	FmgrInfo   procedure;
+	FunctionCallInfoData fcinfo;
+
+	if (!RegProcedureIsValid(amoptions))
+		return amdata;
+
+	fmgr_info(amoptions, &procedure);
+
+	/*
+	 * have the seqam's seqparams proc do it's work.
+	 */
+	InitFunctionCallInfoData(fcinfo, &procedure, 3, InvalidOid, NULL, NULL);
+
+	fcinfo.arg[0] = PointerGetDatum(params);
+	fcinfo.arg[1] = amdata;
+	fcinfo.arg[2] = BoolGetDatum(isInit);
+	fcinfo.argnull[0] = false;
+	fcinfo.argnull[1] = false;
+	fcinfo.argnull[2] = false;
+
+	return 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));
+	if (!HeapTupleIsValid(tuple))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("sequence access method \"%s\" does not exist",
+						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 am \"%s\" does not exist",
+						amname)));
+	return result;
+}
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index b257b02..3a6a597 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 3b89dd0..7078f9c 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -14,13 +14,19 @@
  */
 #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/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"
@@ -72,6 +78,7 @@ typedef struct SeqTableData
 	/* if last != cached, we have not used up all the cached values */
 	int64		increment;		/* copy of sequence's increment field */
 	/* note that increment is zero until we first do read_seq_tuple() */
+	Datum		amdata;			/* private data of the SeqAm */
 } SeqTableData;
 
 typedef SeqTableData *SeqTable;
@@ -95,7 +102,14 @@ 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 tup, Page page);
+static void  replace_sequence_tuple(Relation seqrel, Buffer buf,
+									HeapTuple tuple, HeapTuple newtup);
+static void seqrel_update_relam(Oid seqoid, Oid seqamid);
+static HeapTuple seqtup_update_amdata(HeapTuple tuple, TupleDesc tupdesc, Datum amdata);
+static Datum init_seqam(Oid oldAM, Oid *newAM, char *accessMethod,
+						List *seqoptions, List *reloptions, Datum amdata,
+						bool isInit);
 
 /*
  * DefineSequence
@@ -108,6 +122,7 @@ DefineSequence(CreateSeqStmt *seq)
 	List	   *owned_by;
 	CreateStmt *stmt = makeNode(CreateStmt);
 	Oid			seqoid;
+	Oid			seqamid;
 	Relation	rel;
 	HeapTuple	tuple;
 	TupleDesc	tupDesc;
@@ -115,6 +130,7 @@ DefineSequence(CreateSeqStmt *seq)
 	bool		null[SEQ_COL_LASTCOL];
 	int			i;
 	NameData	name;
+	Datum		amdata;
 
 	/* Unlogged sequences are not implemented -- not clear if useful. */
 	if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
@@ -140,8 +156,10 @@ DefineSequence(CreateSeqStmt *seq)
 		}
 	}
 
-	/* Check and set all option values */
+	/* Check and set all param values */
 	init_params(seq->options, true, &new, &owned_by);
+	amdata = init_seqam(InvalidOid, &seqamid, seq->accessMethod,
+						seq->options, seq->amoptions, (Datum) 0, true);
 
 	/*
 	 * Create relation (and fill value[] and null[] for the tuple)
@@ -218,6 +236,14 @@ DefineSequence(CreateSeqStmt *seq)
 				coldef->colname = "is_called";
 				value[i - 1] = BoolGetDatum(false);
 				break;
+			case SEQ_COL_AMDATA:
+				coldef->typeName = makeTypeNameFromOid(BYTEAOID, -1);
+				coldef->colname = "amdata";
+				if (PointerIsValid(DatumGetPointer(amdata)))
+					value[i - 1] = amdata;
+				else
+					null[i - 1] = true;
+				break;
 		}
 		stmt->tableElts = lappend(stmt->tableElts, coldef);
 	}
@@ -233,6 +259,14 @@ DefineSequence(CreateSeqStmt *seq)
 	seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, 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);
 
@@ -270,6 +304,8 @@ ResetSequence(Oid seq_relid)
 	Buffer		buf;
 	HeapTupleData seqtuple;
 	HeapTuple	tuple;
+	Datum		amdata;
+	bool		amdata_isnull;
 
 	/*
 	 * Read the old sequence.  This does a bit more work than really
@@ -279,10 +315,21 @@ ResetSequence(Oid seq_relid)
 	init_sequence(seq_relid, &elm, &seq_rel);
 	(void) read_seq_tuple(elm, seq_rel, &buf, &seqtuple);
 
-	/*
-	 * Copy the existing sequence tuple.
-	 */
-	tuple = heap_copytuple(&seqtuple);
+	seq = (Form_pg_sequence) GETSTRUCT(&seqtuple);
+
+	/* Get original amdata. */
+	amdata = fastgetattr(&seqtuple, SEQ_COL_AMDATA,
+						 RelationGetDescr(seq_rel), &amdata_isnull);
+	if (amdata_isnull)
+		amdata = (Datum) 0;
+
+	/* Call into the sequence AM. */
+	amdata = sequence_setval(seq_rel, seq->last_value,
+							 seq->start_value, amdata);
+
+	/* Build new tuple with updated amdata and point seq to it. */
+	tuple = seqtup_update_amdata(&seqtuple, RelationGetDescr(seq_rel), amdata);
+	seq = (Form_pg_sequence) GETSTRUCT(tuple);
 
 	/* Now we're done with the old page */
 	UnlockReleaseBuffer(buf);
@@ -291,7 +338,6 @@ ResetSequence(Oid seq_relid)
 	 * Modify the copied tuple to execute the restart (compare the RESTART
 	 * action in AlterSequence)
 	 */
-	seq = (Form_pg_sequence) GETSTRUCT(tuple);
 	seq->last_value = seq->start_value;
 	seq->is_called = false;
 	seq->log_cnt = 0;
@@ -305,7 +351,9 @@ ResetSequence(Oid seq_relid)
 							  InvalidMultiXactId);
 
 	/*
-	 * Insert the modified tuple into the new storage file.
+	 * Insert the modified tuple into the new storage file. This will log
+	 * superflously log the old values, but this isn't a performance critical
+	 * path...
 	 */
 	fill_seq_with_data(seq_rel, tuple);
 
@@ -366,27 +414,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;
-		XLogRecData rdata[2];
-
-		xlrec.node = rel->rd_node;
-		rdata[0].data = (char *) &xlrec;
-		rdata[0].len = sizeof(xl_seq_rec);
-		rdata[0].buffer = InvalidBuffer;
-		rdata[0].next = &(rdata[1]);
-
-		rdata[1].data = (char *) tuple->t_data;
-		rdata[1].len = tuple->t_len;
-		rdata[1].buffer = InvalidBuffer;
-		rdata[1].next = NULL;
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
-
-		PageSetLSN(page, recptr);
-	}
+	log_sequence_tuple(rel, tuple, page);
 
 	END_CRIT_SECTION();
 
@@ -402,13 +430,17 @@ Oid
 AlterSequence(AlterSeqStmt *stmt)
 {
 	Oid			relid;
+	Oid			seqamid;
 	SeqTable	elm;
 	Relation	seqrel;
 	Buffer		buf;
 	HeapTupleData seqtuple;
+	HeapTuple	tuple;
 	Form_pg_sequence seq;
 	FormData_pg_sequence new;
 	List	   *owned_by;
+	Datum		amdata;
+	bool		amdata_isnull;
 
 	/* Open and lock sequence. */
 	relid = RangeVarGetRelid(stmt->sequence, AccessShareLock, stmt->missing_ok);
@@ -433,45 +465,46 @@ AlterSequence(AlterSeqStmt *stmt)
 	/* Copy old values of options into workspace */
 	memcpy(&new, seq, sizeof(FormData_pg_sequence));
 
+	/* Get original amdata. */
+	amdata = fastgetattr(&seqtuple, SEQ_COL_AMDATA,
+						 RelationGetDescr(seqrel), &amdata_isnull);
+	if (amdata_isnull)
+		amdata = (Datum) 0;
+
 	/* Check and set new values */
 	init_params(stmt->options, false, &new, &owned_by);
+	amdata = init_seqam(seqrel->rd_rel->relam, &seqamid, stmt->accessMethod,
+						stmt->options, stmt->amoptions, amdata, false);
+
+	/*
+	 * Change the SeqAm, if requested, using a transactional update.
+	 */
+	seqrel_update_relam(relid, seqamid);
+
+	/* Build new tuple with updated amdata and point seq to it. */
+	tuple = seqtup_update_amdata(&seqtuple, RelationGetDescr(seqrel), amdata);
+	seq = (Form_pg_sequence) GETSTRUCT(tuple);
+
+	/*
+	 * Copy values.
+	 * XXX: there has to be a better way...
+	 */
+	seq->last_value = new.last_value;
+	seq->start_value = new.start_value;
+	seq->increment_by = new.increment_by;
+	seq->max_value = new.max_value;
+	seq->min_value = new.min_value;
+	seq->cache_value = new.cache_value;
+	seq->log_cnt = new.log_cnt;
+	seq->is_cycled = new.is_cycled;
+	seq->is_called = new.is_called;
 
 	/* 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;
 
 	/* Now okay to update the on-disk tuple */
-	START_CRIT_SECTION();
-
-	memcpy(seq, &new, sizeof(FormData_pg_sequence));
-
-	MarkBufferDirty(buf);
-
-	/* XLOG stuff */
-	if (RelationNeedsWAL(seqrel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-		XLogRecData rdata[2];
-		Page		page = BufferGetPage(buf);
-
-		xlrec.node = seqrel->rd_node;
-		rdata[0].data = (char *) &xlrec;
-		rdata[0].len = sizeof(xl_seq_rec);
-		rdata[0].buffer = InvalidBuffer;
-		rdata[0].next = &(rdata[1]);
-
-		rdata[1].data = (char *) seqtuple.t_data;
-		rdata[1].len = seqtuple.t_len;
-		rdata[1].buffer = InvalidBuffer;
-		rdata[1].next = NULL;
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
-
-		PageSetLSN(page, recptr);
-	}
-
-	END_CRIT_SECTION();
+	replace_sequence_tuple(seqrel, buf, &seqtuple, tuple);
 
 	UnlockReleaseBuffer(buf);
 
@@ -486,6 +519,49 @@ AlterSequence(AlterSeqStmt *stmt)
 	return relid;
 }
 
+/*
+ * sequence_request_update
+ *
+ * This function should be used by SeqAMs to request update callback
+ * when they need to do background processing on the sequence.
+ */
+void
+sequence_request_update(Oid seq_relid)
+{
+	Relation	seq_rel;
+	SeqTable	elm;
+	Buffer		buf;
+	HeapTupleData seqtuple;
+	HeapTuple	tuple;
+	Datum		amdata;
+	bool		amdata_isnull;
+
+	/*
+	 * 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.
+	 */
+	init_sequence(seq_relid, &elm, &seq_rel);
+	(void) read_seq_tuple(elm, seq_rel, &buf, &seqtuple);
+
+	/* Get original amdata. */
+	amdata = fastgetattr(&seqtuple, SEQ_COL_AMDATA,
+						 RelationGetDescr(seq_rel), &amdata_isnull);
+	if (amdata_isnull)
+		amdata = (Datum) 0;
+
+	/* Call into the sequence AM. */
+	amdata = sequence_update(seq_rel, amdata);
+
+	/* Build new tuple with updated amdata. */
+	tuple = seqtup_update_amdata(&seqtuple, RelationGetDescr(seq_rel), amdata);
+
+	replace_sequence_tuple(seq_rel, buf, &seqtuple, tuple);
+
+	/* Now we're done with the old page */
+	UnlockReleaseBuffer(buf);
+	relation_close(seq_rel, NoLock);
+}
 
 /*
  * Note: nextval with a text argument is no longer exported as a pg_proc
@@ -522,6 +598,10 @@ 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)
 {
@@ -535,13 +615,15 @@ nextval_internal(Oid relid)
 				maxv,
 				minv,
 				cache,
-				log,
 				fetch,
-				last;
-	int64		result,
-				next,
-				rescnt = 0;
-	bool		logit = false;
+				log,
+				value,
+				nallocated = 0,
+				last,
+				result;
+	bool		logit = false,
+				is_cycled;
+	Datum		amdata = (Datum) 0;
 
 	/* open and AccessShareLock sequence */
 	init_sequence(relid, &elm, &seqrel);
@@ -571,18 +653,16 @@ nextval_internal(Oid relid)
 	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
 	page = BufferGetPage(buf);
 
-	last = next = result = seq->last_value;
+	value = seq->last_value;
 	incby = seq->increment_by;
 	maxv = seq->max_value;
 	minv = seq->min_value;
-	fetch = cache = seq->cache_value;
+	is_cycled = seq->is_cycled;
+	fetch = 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
@@ -612,72 +692,39 @@ nextval_internal(Oid relid)
 		}
 	}
 
-	while (fetch)				/* try to fetch cache [+ log ] numbers */
+	/* Call into sequnce AM code. */
+	if (fetch)
 	{
-		/*
-		 * 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];
+		bool	amdata_isnull;
 
-					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];
+		/* Get original amdata. */
+		amdata = fastgetattr(&seqtuple, SEQ_COL_AMDATA,
+							 RelationGetDescr(seqrel), &amdata_isnull);
+		if (amdata_isnull)
+			amdata = (Datum) 0;
 
-					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 */
-		}
+		amdata = sequence_alloc(seqrel, &value, fetch, minv, maxv, incby,
+								is_cycled, amdata, &nallocated, &logit);
+	}
+
+	cache = Min(seq->cache_value, nallocated);
+
+	if (!seq->is_called)
+		result = seq->last_value;		/* return last_value if not is_called */
+	else
+	{
+		Assert(nallocated);
+		result = value;
+		cache--;
 	}
 
-	log -= fetch;				/* adjust for any unfetched numbers */
+	log -= cache + (fetch-nallocated);
 	Assert(log >= 0);
 
+	last = result;
+	sequence_increment(seqrel, &last, cache, minv, maxv,
+					   incby, is_cycled, false);
+
 	/* save info in local cache */
 	elm->last = result;			/* last returned number */
 	elm->cached = last;			/* last fetched number */
@@ -685,53 +732,67 @@ 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))
+	if (logit)
 	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-		XLogRecData rdata[2];
-
 		/*
 		 * 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.
 		 */
+		Form_pg_sequence logseq;
+		Page		temppage,
+					page;
+		HeapTuple	tuple;
+		int64		next = value;
+
+		sequence_increment(seqrel, &next, nallocated, minv, maxv,
+						   incby, is_cycled, false);
+
+		/* Build new tuple with updated amdata. */
+		tuple = seqtup_update_amdata(&seqtuple, RelationGetDescr(seqrel), amdata);
+		logseq = (Form_pg_sequence) GETSTRUCT(tuple);
+
+		logseq->last_value = next;
+		logseq->is_called = true;
+		logseq->log_cnt = 0;
 
-		/* set values that will be saved in xlog */
-		seq->last_value = next;
-		seq->is_called = true;
-		seq->log_cnt = 0;
+		/* Replace the original tuple with the updated one in-place */
+		page = BufferGetPage(buf);
 
-		xlrec.node = seqrel->rd_node;
-		rdata[0].data = (char *) &xlrec;
-		rdata[0].len = sizeof(xl_seq_rec);
-		rdata[0].buffer = InvalidBuffer;
-		rdata[0].next = &(rdata[1]);
+		temppage = PageGetTempPageCopySpecial(page);
 
-		rdata[1].data = (char *) seqtuple.t_data;
-		rdata[1].len = seqtuple.t_len;
-		rdata[1].buffer = InvalidBuffer;
-		rdata[1].next = NULL;
+		if (PageAddItem(temppage, (Item) tuple->t_data, tuple->t_len,
+						FirstOffsetNumber, false, false) == InvalidOffsetNumber)
+			elog(PANIC, "replace_sequence_tuple: failed to add item to page");
 
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
+		PageSetLSN(temppage, PageGetLSN(page));
 
-		PageSetLSN(page, recptr);
+		START_CRIT_SECTION();
+
+		PageRestoreTempPage(temppage, page);
+
+		/*
+		 * We must mark the buffer dirty before doing XLogInsert(); see notes in
+		 * SyncOneBuffer(). However, we changed the buffer to the contents of
+		 * a "future" state. 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);
+
+		seqtuple.t_len = tuple->t_len;
+
+		log_sequence_tuple(seqrel, &seqtuple, page);
+	}
+	else
+	{
+		/* the seq changes should mark the buffer dirty in any case */
+		START_CRIT_SECTION();
+		MarkBufferDirty(buf);
 	}
 
 	/* Now update sequence tuple to the intended final state */
@@ -748,6 +809,7 @@ nextval_internal(Oid relid)
 	return result;
 }
 
+
 Datum
 currval_oid(PG_FUNCTION_ARGS)
 {
@@ -834,7 +896,10 @@ do_setval(Oid relid, int64 next, bool iscalled)
 	Relation	seqrel;
 	Buffer		buf;
 	HeapTupleData seqtuple;
+	HeapTuple	tuple;
 	Form_pg_sequence seq;
+	Datum		amdata;
+	bool		amdata_isnull;
 
 	/* open and AccessShareLock sequence */
 	init_sequence(relid, &elm, &seqrel);
@@ -868,6 +933,21 @@ do_setval(Oid relid, int64 next, bool iscalled)
 						bufm, bufx)));
 	}
 
+	/* Get original amdata. */
+	amdata = fastgetattr(&seqtuple, SEQ_COL_AMDATA,
+						 RelationGetDescr(seqrel), &amdata_isnull);
+	if (amdata_isnull)
+		amdata = (Datum) 0;
+
+	/* Call into the sequence AM. */
+	amdata = sequence_setval(seqrel, seq->last_value, next, amdata);
+
+	/* Build new tuple with updated amdata and point seq to it. */
+	tuple = seqtup_update_amdata(&seqtuple, RelationGetDescr(seqrel), amdata);
+	seq = (Form_pg_sequence) GETSTRUCT(tuple);
+
+	/* common logic we don't have to duplicate in every AM implementation */
+
 	/* Set the currval() state only if iscalled = true */
 	if (iscalled)
 	{
@@ -878,40 +958,12 @@ do_setval(Oid relid, int64 next, bool iscalled)
 	/* 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();
-
 	seq->last_value = next;		/* last fetched number */
 	seq->is_called = iscalled;
 	seq->log_cnt = 0;
 
-	MarkBufferDirty(buf);
-
-	/* XLOG stuff */
-	if (RelationNeedsWAL(seqrel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-		XLogRecData rdata[2];
-		Page		page = BufferGetPage(buf);
-
-		xlrec.node = seqrel->rd_node;
-		rdata[0].data = (char *) &xlrec;
-		rdata[0].len = sizeof(xl_seq_rec);
-		rdata[0].buffer = InvalidBuffer;
-		rdata[0].next = &(rdata[1]);
-
-		rdata[1].data = (char *) seqtuple.t_data;
-		rdata[1].len = seqtuple.t_len;
-		rdata[1].buffer = InvalidBuffer;
-		rdata[1].next = NULL;
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
-
-		PageSetLSN(page, recptr);
-	}
-
-	END_CRIT_SECTION();
+	/* ready to change the on-disk (or really, in-buffer) tuple */
+	replace_sequence_tuple(seqrel, buf, &seqtuple, tuple);
 
 	UnlockReleaseBuffer(buf);
 
@@ -1040,6 +1092,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 		elm->lxid = InvalidLocalTransactionId;
 		elm->last_valid = false;
 		elm->last = elm->cached = elm->increment = 0;
+		elm->amdata = PointerGetDatum(NULL);
 	}
 
 	/*
@@ -1130,15 +1183,15 @@ read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
 }
 
 /*
- * 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;
@@ -1148,13 +1201,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)
 		{
@@ -1399,7 +1452,7 @@ init_params(List *options, bool isInit,
 }
 
 /*
- * 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
@@ -1415,8 +1468,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,
@@ -1548,6 +1600,134 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
+/*
+ * 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 tup, Page page)
+{
+	xl_seq_rec	xlrec;
+	XLogRecPtr	recptr;
+	XLogRecData rdata[2];
+
+	xlrec.node = seqrel->rd_node;
+	rdata[0].data = (char *) &xlrec;
+	rdata[0].len = sizeof(xl_seq_rec);
+	rdata[0].buffer = InvalidBuffer;
+	rdata[0].next = &(rdata[1]);
+
+	rdata[1].data = (char *) tup->t_data;
+	rdata[1].len = tup->t_len;
+	rdata[1].buffer = InvalidBuffer;
+	rdata[1].next = NULL;
+
+	recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG, rdata);
+
+	PageSetLSN(page, recptr);
+}
+
+/*
+ * Replace the sequence tuple in a buffer and save it to the disk.
+ */
+static void
+replace_sequence_tuple(Relation seqrel, Buffer buf, HeapTuple tuple, HeapTuple newtup)
+{
+	Page temppage, page;
+
+	page = BufferGetPage(buf);
+
+	temppage = PageGetTempPageCopySpecial(page);
+
+	if (PageAddItem(temppage, (Item) newtup->t_data, newtup->t_len,
+					FirstOffsetNumber, false, false) == InvalidOffsetNumber)
+		elog(PANIC, "replace_sequence_tuple: failed to add item to page");
+
+	PageSetLSN(temppage, PageGetLSN(page));
+
+	START_CRIT_SECTION();
+
+	PageRestoreTempPage(temppage, page);
+
+	MarkBufferDirty(buf);
+
+	tuple->t_len = newtup->t_len;
+
+	log_sequence_tuple(seqrel, tuple, page);
+
+	END_CRIT_SECTION();
+}
+
+/*
+ * Return copy of the sequence tuple with updated amdata.
+ */
+static HeapTuple
+seqtup_update_amdata(HeapTuple tuple, TupleDesc tupdesc, Datum amdata)
+{
+	Datum		values[SEQ_COL_LASTCOL];
+	bool		nulls[SEQ_COL_LASTCOL];
+	bool		repls[SEQ_COL_LASTCOL];
+	HeapTuple	newtup;
+
+	/* Build new tuple with updated amdata */
+	memset(values, 0, sizeof(values));
+	memset(nulls, false, sizeof(nulls));
+	memset(repls, false, sizeof(repls));
+
+	if (PointerIsValid(DatumGetPointer(amdata)))
+		values[SEQ_COL_AMDATA - 1] = amdata;
+	else
+		nulls[SEQ_COL_AMDATA - 1] = true;
+
+	repls[SEQ_COL_AMDATA - 1] = true;
+
+	newtup = heap_modify_tuple(tuple, tupdesc, values, nulls, repls);
+
+	/*
+	 * Sequence tuples must be frozen, because VACUUM does not examine
+	 * sequence table.
+	 */
+	HeapTupleHeaderSetXmin(newtup->t_data, FrozenTransactionId);
+	HeapTupleHeaderSetXminFrozen(newtup->t_data);
+	HeapTupleHeaderSetCmin(newtup->t_data, FirstCommandId);
+	HeapTupleHeaderSetXmax(newtup->t_data, InvalidTransactionId);
+	newtup->t_data->t_infomask |= HEAP_XMAX_INVALID;
+
+	return newtup;
+}
 
 void
 seq_redo(XLogRecPtr lsn, XLogRecord *record)
@@ -1602,6 +1782,7 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
 	pfree(localpage);
 }
 
+
 /*
  * Flush cached sequence information.
  */
@@ -1616,3 +1797,184 @@ ResetSequenceCaches(void)
 
 	last_used_seq = NULL;
 }
+
+static Datum
+init_seqam(Oid oldAM, Oid *newAM, char *accessMethod, List *seqparams,
+		   List *reloptions, Datum amdata, bool isInit)
+{
+	Datum       reloptions_parsed;
+	Form_pg_seqam seqamForm;
+	HeapTuple   tuple = NULL;
+	char	   *validnsps[] = {NULL, NULL};
+	Datum		res;
+
+	if (oldAM && accessMethod == NULL)
+		*newAM = oldAM;
+	else if (accessMethod == NULL || strcmp(accessMethod, DEFAULT_SEQAM) == 0)
+		*newAM = GetDefaultSeqAM();
+	else
+		*newAM = get_seqam_oid(accessMethod, false);
+
+	tuple = SearchSysCache1(SEQAMOID, ObjectIdGetDatum(*newAM));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", *newAM);
+
+	seqamForm = (Form_pg_seqam) GETSTRUCT(tuple);
+
+	/* First process/validate the standard sequence params */
+	res = sequence_seqparams(seqamForm->seqamseqparams, seqparams,
+							 amdata, isInit);
+
+	/* 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_parsed = transformRelOptions((Datum) NULL, reloptions,
+											NULL, validnsps, false, false);
+
+	(void) sequence_reloptions(seqamForm->seqamreloptions, reloptions_parsed, true);
+
+	ReleaseSysCache(tuple);
+
+	return res;
+}
+
+
+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;
+}
+
+
+/*------------------------------------------------------------
+ *
+ * Sequence Access Manager = LOCAL functions
+ *
+ *------------------------------------------------------------
+ */
+
+/*
+ * sequence_local_alloc()
+ *
+ * Allocate new range of values for a local sequence.
+ */
+Datum
+sequence_local_alloc(PG_FUNCTION_ARGS)
+{
+	Relation	seqrel = (Relation) PG_GETARG_POINTER(0);
+	int64	   *current_value = (int64 *) PG_GETARG_POINTER(1);
+	int64		fetch = PG_GETARG_INT64(2);
+	int64		min_value = PG_GETARG_INT64(3);
+	int64		max_value = PG_GETARG_INT64(4);
+	int64		increment_by = PG_GETARG_INT64(5);
+	bool		is_cycled = PG_GETARG_INT64(6);
+	int64	   *nallocated = (int64 *) PG_GETARG_POINTER(8);
+	int64		next,
+				rescnt = 0;
+
+	next = *current_value;
+	rescnt = sequence_increment(seqrel, &next, 1, min_value, max_value,
+								increment_by, is_cycled, true);
+	*current_value = next;
+	fetch--;
+
+	if (fetch)
+		rescnt += sequence_increment(seqrel, &next, fetch, min_value, max_value,
+									 increment_by, is_cycled, false);
+
+	*nallocated = rescnt;
+
+	PG_RETURN_NULL();
+}
+
+/*
+ * sequence_local_options()
+ *
+ * Verify the options of a local sequence.
+ */
+Datum
+sequence_local_options(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();
+}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ecdff1e..90f043a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9010,6 +9010,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 21b070a..53b7fbd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3330,7 +3330,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;
@@ -3343,7 +3345,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 358395f..3c37de9 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1566,7 +1566,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;
@@ -1577,7 +1579,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 c98c27a..e8d0d5e 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"
@@ -3519,7 +3520,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;
@@ -3541,7 +3568,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;
 				}
@@ -3549,11 +3600,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; }
@@ -3612,7 +3686,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/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index 6351a9b..dfd3592 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -285,7 +285,10 @@ PageAddItem(Page page,
 	upper = (int) phdr->pd_upper - (int) alignedSize;
 
 	if (lower > upper)
+	{
+		elog(WARNING, "lower %d bigger than upper %d, offsetNumber %d", lower, upper, offsetNumber);
 		return InvalidOffsetNumber;
+	}
 
 	/*
 	 * OK to insert the item.  First, shuffle the existing pointers if needed.
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 c813779..1799cce 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -50,6 +50,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"
@@ -264,6 +265,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);
@@ -1053,11 +1055,14 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	else
 		relation->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);
@@ -1533,6 +1538,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
@@ -4785,6 +4823,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 8111b93..5eba03b 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -27,6 +27,7 @@
 #endif
 
 #include "access/gin.h"
+#include "access/seqam.h"
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
@@ -2782,6 +2783,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 1a9e82e..6f896aa 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -14578,7 +14578,8 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			   *incby,
 			   *maxv = NULL,
 			   *minv = NULL,
-			   *cache;
+			   *cache,
+			   *amname = "local";
 	char		bufm[100],
 				bufx[100];
 	bool		cycled;
@@ -14648,15 +14649,40 @@ dumpSequence(Archive *fout, 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 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
 	 */
@@ -14698,6 +14724,7 @@ dumpSequence(Archive *fout, 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));
@@ -14764,8 +14791,6 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
-	PQclear(res);
-
 	destroyPQExpBuffer(query);
 	destroyPQExpBuffer(delqry);
 	destroyPQExpBuffer(labelq);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 267f365..5df2b85 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, false);
-		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,8 @@ 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);
+	if (tableinfo.relkind == 'S')
+		appendPQExpBufferStr(&buf, " AND attname <> 'amdata'");
 	appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
 
 	res = PSQLexec(buf.data, false);
@@ -1446,6 +1424,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, false);
+		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 +1768,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, false);
+
+		/*
+		 * 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 +1808,8 @@ describeOneTableDetails(const char *schemaname,
 						  oid);
 
 		result = PSQLexec(buf.data, false);
+
+		/* Same logic as above, only print result when we get one row. */
 		if (!result)
 			goto error_return;
 		else if (PQntuples(result) == 1)
@@ -1783,11 +1819,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 c226448..47ae485 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -45,8 +45,10 @@ typedef enum relopt_kind
 	RELOPT_KIND_TABLESPACE = (1 << 7),
 	RELOPT_KIND_SPGIST = (1 << 8),
 	RELOPT_KIND_VIEW = (1 << 9),
+	RELOPT_KIND_SEQUENCE = (1 << 10),
+
 	/* if you add a new kind, make sure you update "last_default" too */
-	RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_VIEW,
+	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;
@@ -271,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..1664b74
--- /dev/null
+++ b/src/include/access/seqam.h
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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"
+
+extern char *default_seqam;
+
+extern Oid GetDefaultSeqAM(void);
+
+extern Datum sequence_alloc(Relation seqRelation, int64 *current_value,
+							int64 nrequested, int64 min_value,
+							int64 max_value, int64 increment_by,
+							bool is_cycled, Datum amdata,
+							int64 *nallocated, bool *xlog_needed);
+
+extern Datum sequence_setval(Relation seqRelation, int64 current_value,
+							 int64 new_value, Datum amdata);
+extern Datum sequence_update(Relation seqRelation, Datum amdata);
+extern Datum sequence_seqparams(RegProcedure amoptions, List *params,
+								Datum amdata, bool isInit);
+extern void sequence_request_update(Oid seqid);
+
+extern Datum sequence_local_alloc(PG_FUNCTION_ARGS);
+extern Datum sequence_local_options(PG_FUNCTION_ARGS);
+
+extern Oid get_seqam_oid(const char *sequencename, bool missing_ok);
+
+extern int64 sequence_increment(Relation seqrel, int64 *value, int64 incnum,
+								int64 minv, int64 maxv, int64 incby,
+								bool is_cycled, bool report_errors);
+
+#endif   /* SEQAM_H */
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 870692c..e4d585f 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 4736532..46f766f 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4987,6 +4987,11 @@ 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 (  sequence_local_alloc	   PGNSP PGUID 12 1 0 0 0 f f f f t f s 10 0 2281 "2281 2281 2281 2281 2281 2281 2281 2281 2281 2281" _null_ _null_ _null_ _null_ sequence_local_alloc _null_ _null_ _null_ ));
+DESCR("Local SequenceAM allocation");
+DATA(insert OID = 6024 (  sequence_local_options	   PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 2281 "2281 16" _null_ _null_ _null_ _null_ sequence_local_options _null_ _null_ _null_ ));
+DESCR("Local SequenceAM options");
+
 /* 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..f025e76
--- /dev/null
+++ b/src/include/catalog/pg_seqam.h
@@ -0,0 +1,74 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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		seqamalloc;			/* get next allocation of range of values function */
+	regproc		seqamsetval;		/* set value function */
+	regproc		seqamupdate;		/* update callback */
+	regproc		seqamseqparams;		/* process standard sequence params */
+	regproc		seqamreloptions;	/* parse AM-specific options */
+} 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						6
+#define Anum_pg_seqam_amname				1
+#define Anum_pg_seqam_amalloc				2
+#define Anum_pg_seqam_amsetval				3
+#define Anum_pg_seqam_amupdate				4
+#define Anum_pg_seqam_amseqoptions			5
+#define Anum_pg_seqam_amreloptions			6
+
+/* ----------------
+ *		initial contents of pg_seqam
+ * ----------------
+ */
+
+DATA(insert OID = 2 (  local		sequence_local_alloc - - - sequence_local_options));
+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 914d155..d6d0d78 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -31,6 +31,7 @@ typedef struct FormData_pg_sequence
 	int64		log_cnt;
 	bool		is_cycled;
 	bool		is_called;
+	bytea		amdata;
 } FormData_pg_sequence;
 
 typedef FormData_pg_sequence *Form_pg_sequence;
@@ -49,9 +50,10 @@ typedef FormData_pg_sequence *Form_pg_sequence;
 #define SEQ_COL_LOG				8
 #define SEQ_COL_CYCLE			9
 #define SEQ_COL_CALLED			10
+#define SEQ_COL_AMDATA			11
 
 #define SEQ_COL_FIRSTCOL		SEQ_COL_NAME
-#define SEQ_COL_LASTCOL			SEQ_COL_CALLED
+#define SEQ_COL_LASTCOL			SEQ_COL_AMDATA
 
 /* XLOG stuff */
 #define XLOG_SEQ_LOG			0x00
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index cef9544..e04c05d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2011,8 +2011,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 +2022,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 66b5cd3..68c7261 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -383,6 +383,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 198b98f..9d88062 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"
@@ -49,10 +50,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;
@@ -62,6 +65,16 @@ typedef struct RelationAmInfo
 	FmgrInfo	ammarkpos;
 	FmgrInfo	amrestrpos;
 	FmgrInfo	amcanreturn;
+	FmgrInfo	amcostestimate;
+
+	/* pg_seqam only */
+	FmgrInfo	seqamalloc;
+	FmgrInfo	seqamsetval;
+	FmgrInfo	seqamupdate;
+	FmgrInfo	seqamseqparams;
+
+	/* Common */
+	FmgrInfo	amoptions;
 } RelationAmInfo;
 
 
@@ -131,23 +144,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 +173,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/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 2c8ec11..ddd96d5 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -123,6 +123,7 @@ pg_range|t
 pg_rewrite|t
 pg_rowsecurity|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 a27b5fd..a6d5de5 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -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 | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called | amdata 
+---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+--------
+ foo_seq       |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | 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 | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called | amdata 
+---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------+--------
+ foo_seq       |          2 |           1 |            1 | 9223372036854775807 |         1 |           1 |      31 | f         | 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..5e98b24 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -109,6 +109,7 @@ SELECT table_name, column_name, is_updatable
  ro_view19  | log_cnt       | NO
  ro_view19  | is_cycled     | NO
  ro_view19  | is_called     | NO
+ ro_view19  | amdata        | NO
  ro_view2   | a             | NO
  ro_view2   | b             | NO
  ro_view20  | a             | NO
@@ -134,7 +135,7 @@ SELECT table_name, column_name, is_updatable
  rw_view16  | a             | YES
  rw_view16  | b             | YES
  rw_view16  | aa            | YES
-(46 rows)
+(47 rows)
 
 -- Read-only views
 DELETE FROM ro_view1;
-- 
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