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 b5fd30a..950c291 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -274,6 +274,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
@@ -809,6 +810,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;
@@ -1219,13 +1223,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..c0106c6
--- /dev/null
+++ b/src/backend/access/sequence/seqam.c
@@ -0,0 +1,253 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqam.c
+ *	  sequence access method routines
+ *
+ * Portions Copyright (c) 1996-2013, 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) \
+do { \
+	procedure = &seqRelation->rd_aminfo->pname; \
+	if (!OidIsValid(procedure->fn_oid)) \
+	{ \
+		RegProcedure	procOid = seqRelation->rd_seqam->pname; \
+		if (!RegProcedureIsValid(procOid)) \
+			elog(ERROR, "invalid %s regproc", CppAsString(pname)); \
+		fmgr_info_cxt(procOid, procedure, seqRelation->rd_indexcxt); \
+	} \
+} 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_reloptions	- process options - located in reloptions.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * sequence_alloc - allocate sequence values in a sequence
+ */
+void
+sequence_alloc(Relation seqRelation, SeqTable seq_elem, Buffer buf, HeapTuple tup)
+{
+	FmgrInfo   *procedure;
+
+	Assert(RelationIsValid(seqRelation));
+	Assert(PointerIsValid(seqRelation->rd_seqam));
+	Assert(OidIsValid(seqRelation->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamalloc);
+
+	/*
+	 * have the seqam's alloc proc do all the work.
+	 */
+	FunctionCall4(procedure,
+				  PointerGetDatum(seqRelation),
+				  PointerGetDatum(seq_elem),
+				  Int32GetDatum(buf),
+				  PointerGetDatum(tup));
+}
+
+/*
+ * sequence_setval - set sequence values in a sequence
+ */
+void
+sequence_setval(Relation seqRelation, SeqTable seq_elem, Buffer buf, HeapTuple tup, int64 next, bool iscalled)
+{
+	FmgrInfo   *procedure;
+
+	Assert(RelationIsValid(seqRelation));
+	Assert(PointerIsValid(seqRelation->rd_seqam));
+	Assert(OidIsValid(seqRelation->rd_rel->relam));
+
+	GET_SEQAM_PROCEDURE(seqamsetval);
+
+	/*
+	 * have the seqam's setval proc do all the work.
+	 */
+	FunctionCall6(procedure,
+				  PointerGetDatum(seqRelation),
+				  PointerGetDatum(seq_elem),
+				  Int32GetDatum(buf),
+				  PointerGetDatum(tup),
+				  Int64GetDatum(next),
+				  BoolGetDatum(iscalled));
+}
+
+/*------------------------------------------------------------
+ *
+ * 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 a974bd5..c85b5d1 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 f3344c6..5ca29a1 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"
@@ -55,32 +61,6 @@ typedef struct sequence_magic
 	uint32		magic;
 } sequence_magic;
 
-/*
- * We store a SeqTable item for every sequence we have touched in the current
- * session.  This is needed to hold onto nextval/currval state.  (We can't
- * rely on the relcache, since it's only, well, a cache, and may decide to
- * discard entries.)
- *
- * XXX We use linear search to find pre-existing SeqTable entries.	This is
- * good when only a small number of sequences are touched in a session, but
- * would suck with many different sequences.  Perhaps use a hashtable someday.
- */
-typedef struct SeqTableData
-{
-	struct SeqTableData *next;	/* link to next SeqTable object */
-	Oid			relid;			/* pg_class OID of this sequence */
-	Oid			filenode;		/* last seen relfilenode of this sequence */
-	LocalTransactionId lxid;	/* xact in which we last did a seq op */
-	bool		last_valid;		/* do we have a valid "last" value? */
-	int64		last;			/* value last returned by nextval */
-	int64		cached;			/* last value already cached for nextval */
-	/* 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() */
-} SeqTableData;
-
-typedef SeqTableData *SeqTable;
-
 static SeqTable seqtab = NULL;	/* Head of list of SeqTable items */
 
 /*
@@ -92,13 +72,12 @@ static SeqTableData *last_used_seq = NULL;
 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 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,
+static void init_params(List *params, 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 seqrel_update_relam(Oid seqoid, Oid seqamid);
+static Oid init_options(char *accessMethod, List *options);
 
 
 /*
@@ -112,6 +91,7 @@ DefineSequence(CreateSeqStmt *seq)
 	List	   *owned_by;
 	CreateStmt *stmt = makeNode(CreateStmt);
 	Oid			seqoid;
+	Oid			seqamid;
 	Relation	rel;
 	HeapTuple	tuple;
 	TupleDesc	tupDesc;
@@ -119,6 +99,9 @@ DefineSequence(CreateSeqStmt *seq)
 	bool		null[SEQ_COL_LASTCOL];
 	int			i;
 	NameData	name;
+	HeapTupleData seqtuple;
+	SeqTable	elm;
+	Buffer		buf;
 
 	/* Unlogged sequences are not implemented -- not clear if useful. */
 	if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
@@ -126,8 +109,9 @@ DefineSequence(CreateSeqStmt *seq)
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("unlogged sequences are not supported")));
 
-	/* Check and set all option values */
+	/* Check and set all param values */
 	init_params(seq->options, true, &new, &owned_by);
+	seqamid = init_options(seq->accessMethod, seq->amoptions);
 
 	/*
 	 * Create relation (and fill value[] and null[] for the tuple)
@@ -203,6 +187,11 @@ 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";
+				null[i - 1] = true;
+				break;
 		}
 		stmt->tableElts = lappend(stmt->tableElts, coldef);
 	}
@@ -218,6 +207,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);
 
@@ -231,6 +228,19 @@ DefineSequence(CreateSeqStmt *seq)
 
 	heap_close(rel, NoLock);
 
+	/*
+	 * reopen relation, read sequence for the benfit of the AM. It would be
+	 * nice to do this with less repetitive work.
+	 */
+	init_sequence(seqoid, &elm, &rel);
+	(void) read_seq_tuple(elm, rel, &buf, &seqtuple);
+
+	/* call into AM */
+	sequence_setval(rel, elm, buf, &seqtuple, new.start_value, false);
+
+	UnlockReleaseBuffer(buf);
+	heap_close(rel, NoLock);
+
 	return seqoid;
 }
 
@@ -273,15 +283,6 @@ ResetSequence(Oid seq_relid)
 	UnlockReleaseBuffer(buf);
 
 	/*
-	 * 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;
-
-	/*
 	 * 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.
@@ -290,14 +291,25 @@ 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);
 
+	/* read from the new relfilenode, pointing into buffer again */
+	seq = read_seq_tuple(elm, seq_rel, &buf, &seqtuple);
+
+	/* call into the sequence am, let it do whatever it wants */
+	sequence_setval(seq_rel, elm, buf, &seqtuple, seq->start_value, false);
+
 	/* 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;
 
+	/* And now done with the old page */
+	UnlockReleaseBuffer(buf);
+
 	relation_close(seq_rel, NoLock);
 }
 
@@ -344,6 +356,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 	 * the right xmin, and (b) REDO of the heap_insert record would re-init
 	 * page and sequence magic number would be lost.  This means two log
 	 * records instead of one :-(
+	 * XXX: Why don't we just pass HEAP_INSERT_SKIP_WAL to heap_insert?
 	 */
 	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
 
@@ -373,27 +386,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 	MarkBufferDirty(buf);
 
 	/* 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();
 
@@ -409,12 +402,14 @@ Oid
 AlterSequence(AlterSeqStmt *stmt)
 {
 	Oid			relid;
+	Oid			seqamid;
 	SeqTable	elm;
 	Relation	seqrel;
 	Buffer		buf;
 	HeapTupleData seqtuple;
+	HeapTuple newtuple;
 	Form_pg_sequence seq;
-	FormData_pg_sequence new;
+	Form_pg_sequence new;
 	List	   *owned_by;
 
 	/* Open and lock sequence. */
@@ -437,11 +432,16 @@ AlterSequence(AlterSeqStmt *stmt)
 	/* lock page' buffer and read tuple into new sequence structure */
 	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
 
-	/* Copy old values of options into workspace */
-	memcpy(&new, seq, sizeof(FormData_pg_sequence));
+	/*
+	 * copy tuple so init_params can scribble on it and error out later without
+	 * causing problems.
+	 */
+	newtuple = heap_copytuple(&seqtuple);
+	new = (Form_pg_sequence) GETSTRUCT(newtuple);
 
 	/* Check and set new values */
-	init_params(stmt->options, false, &new, &owned_by);
+	init_params(stmt->options, false, new, &owned_by);
+	seqamid = init_options(stmt->accessMethod, stmt->amoptions);
 
 	/* Clear local cache so that we don't think we have cached numbers */
 	/* Note that we do not change the currval() state */
@@ -450,33 +450,15 @@ AlterSequence(AlterSeqStmt *stmt)
 	/* Now okay to update the on-disk tuple */
 	START_CRIT_SECTION();
 
-	memcpy(seq, &new, sizeof(FormData_pg_sequence));
+	/* we copy back the tuple, contains new settings but is not yet reset via AM*/
+	Assert(newtuple->t_len == seqtuple.t_len);
+	memcpy(seqtuple.t_data, newtuple->t_data, newtuple->t_len);
 
 	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);
-	}
+	/* call SeqAM, in a crit section since we already modified the tuple */
+	sequence_setval(seqrel, elm, buf, &seqtuple,
+					seq->last_value, seq->is_called);
 
 	END_CRIT_SECTION();
 
@@ -486,6 +468,11 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	/*
+	 * Change the SeqAm, if requested, using a transactional update.
+	 */
+	seqrel_update_relam(relid, seqamid);
+
 	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 
 	relation_close(seqrel, NoLock);
@@ -529,26 +516,20 @@ 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;
+	int64		result;
+
+	/* common code path for all sequence AMs */
 
 	/* open and AccessShareLock sequence */
 	init_sequence(relid, &elm, &seqrel);
@@ -564,7 +545,8 @@ nextval_internal(Oid relid)
 	if (!seqrel->rd_islocaltemp)
 		PreventCommandIfReadOnly("nextval()");
 
-	if (elm->last != elm->cached)		/* some numbers were cached */
+	/* return cached values without entering the sequence am again */
+	if (elm->last != elm->cached)
 	{
 		Assert(elm->last_valid);
 		Assert(elm->increment != 0);
@@ -575,178 +557,14 @@ nextval_internal(Oid relid)
 	}
 
 	/* lock page' buffer and read tuple */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
-	page = BufferGetPage(buf);
-
-	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];
+	read_seq_tuple(elm, seqrel, &buf, &seqtuple);
 
-					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);
-
-	/* save info in local cache */
-	elm->last = result;			/* last returned number */
-	elm->cached = last;			/* last fetched number */
-	elm->last_valid = true;
+	/* call into AM specific code */
+	sequence_alloc(seqrel, elm, buf, &seqtuple);
 
 	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;
-		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.
-		 */
-
-		/* 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;
-		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);
-	}
-
-	/* 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();
+	result = elm->last;
 
 	UnlockReleaseBuffer(buf);
 
@@ -875,51 +693,22 @@ do_setval(Oid relid, int64 next, bool iscalled)
 						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();
+	sequence_setval(seqrel, elm, buf, &seqtuple, next, iscalled);
 
-	seq->last_value = next;		/* last fetched number */
-	seq->is_called = iscalled;
-	seq->log_cnt = 0;
+	Assert(seq->is_called == iscalled);
 
-	MarkBufferDirty(buf);
+	/* common logic we don't have to duplicate in every AM implementation */
 
-	/* XLOG stuff */
-	if (RelationNeedsWAL(seqrel))
+	/* Set the currval() state only if iscalled = true */
+	if (iscalled)
 	{
-		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);
+		elm->last = next;		/* last returned number */
+		elm->last_valid = true;
 	}
 
-	END_CRIT_SECTION();
-
 	UnlockReleaseBuffer(buf);
 
 	relation_close(seqrel, NoLock);
@@ -1002,7 +791,7 @@ open_share_lock(SeqTable seq)
  * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
  * output parameters.
  */
-static void
+void
 init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 {
 	SeqTable	elm;
@@ -1039,6 +828,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 		elm->last_valid = false;
 		elm->last = elm->cached = elm->increment = 0;
 		elm->next = seqtab;
+		elm->am_private = PointerGetDatum(NULL);
 		seqtab = elm;
 	}
 
@@ -1079,7 +869,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
  *
  * Function's return value points to the data payload of the tuple
  */
-static Form_pg_sequence
+Form_pg_sequence
 read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
 {
 	Page		page;
@@ -1130,15 +920,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 +938,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 +1189,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 +1205,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 +1337,42 @@ 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();
+}
 
 void
 seq_redo(XLogRecPtr lsn, XLogRecord *record)
@@ -1603,6 +1428,7 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
 	pfree(localpage);
 }
 
+
 /*
  * Flush cached sequence information.
  */
@@ -1620,3 +1446,279 @@ ResetSequenceCaches(void)
 
 	last_used_seq = NULL;
 }
+
+static Oid
+init_options(char *accessMethod, List *options)
+{
+	Oid         seqamid;
+	Datum       reloptions;
+	Form_pg_seqam seqamForm;
+	HeapTuple   tuple = NULL;
+	char	   *validnsps[] = {NULL, NULL};
+
+	if (accessMethod == NULL || strcmp(accessMethod, DEFAULT_SEQAM) == 0)
+		seqamid = GetDefaultSeqAM();
+	else
+		seqamid = get_seqam_oid(accessMethod, false);
+
+	tuple = SearchSysCache1(SEQAMOID, ObjectIdGetDatum(seqamid));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation %u", seqamid);
+
+	seqamForm = (Form_pg_seqam) GETSTRUCT(tuple);
+
+	/* 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 = transformRelOptions((Datum) NULL, options,
+									 NULL, validnsps, false, false);
+
+	(void) sequence_reloptions(seqamForm->seqamoptions, reloptions, true);
+
+	ReleaseSysCache(tuple);
+
+	return seqamid;
+}
+
+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);
+}
+
+
+/*------------------------------------------------------------
+ *
+ * Sequence Access Manager = LOCAL functions
+ *
+ *------------------------------------------------------------
+ */
+
+/*
+ * seqam_local_alloc()
+ *
+ * Allocate new range of values for a local sequence.
+ */
+void
+sequence_local_alloc(PG_FUNCTION_ARGS)
+{
+	Relation	seqrel = (Relation) PG_GETARG_POINTER(0);
+	SeqTable	elm = (SeqTable) PG_GETARG_POINTER(1);
+	Buffer		buf = (Buffer) PG_GETARG_INT32(2);
+	HeapTuple	seqtuple = (HeapTuple) PG_GETARG_POINTER(3);
+	Page		page;
+	Form_pg_sequence seq;
+	bool		logit = false;
+	int64		incby,
+				maxv,
+				minv,
+				cache,
+				log,
+				fetch,
+				last;
+	int64		result,
+				next;
+	int64		rescnt = 0; /* how many values did we fetch up to now */
+
+	page = BufferGetPage(buf);
+	seq = (Form_pg_sequence) GETSTRUCT(seqtuple);
+
+	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 current last_value if not is_called */
+		fetch--;
+		logit = true;
+	}
+
+	/* check whether value can be satisfied without logging again */
+	if (log < fetch || !seq->is_called || PageGetLSN(page) <= GetRedoRecPtr())
+	{
+		/* forced log to satisfy local demand for values */
+		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))
+			{
+				/* it's ok, only additional cached values exceed maximum */
+				if (rescnt > 0)
+					break;
+				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 */
+		}
+	}
+
+	elm->last = result;
+	elm->cached = last;
+	elm->last_valid = true;
+
+	/* 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);
+
+	if (logit)
+	{
+		/*
+		 * 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.
+		 */
+
+		seq->last_value = next;
+		seq->is_called = true;
+		seq->log_cnt = 0;
+		log_sequence_tuple(seqrel, seqtuple, page);
+	}
+
+	/* Now update sequence tuple to the intended final state */
+	seq->last_value = elm->last; /* last fetched number */
+	seq->is_called = true;
+	seq->log_cnt = log; /* how much is logged */
+
+	result = elm->last;
+
+	END_CRIT_SECTION();
+}
+
+/*
+ * seqam_local_setval()
+ *
+ * Coordinate the setting of a local sequence.
+ */
+void
+sequence_local_setval(PG_FUNCTION_ARGS)
+{
+	Relation	seqrel = (Relation) PG_GETARG_POINTER(0);
+	Buffer		buf = (Buffer) PG_GETARG_INT32(2);
+	HeapTuple	seqtuple = (HeapTuple) PG_GETARG_POINTER(3);
+	int64		next = PG_GETARG_INT64(4);
+	bool		iscalled = PG_GETARG_BOOL(5);
+	Page		page = BufferGetPage(buf);
+	Form_pg_sequence seq = (Form_pg_sequence) GETSTRUCT(seqtuple);
+
+	/* ready to change the on-disk (or really, in-buffer) tuple */
+	START_CRIT_SECTION();
+
+	/* set is_called, all AMs should need to do this */
+	seq->is_called = iscalled;
+	seq->last_value = next;		/* last fetched number */
+	seq->log_cnt = 0;
+
+	MarkBufferDirty(buf);
+
+	log_sequence_tuple(seqrel, seqtuple, page);
+
+	END_CRIT_SECTION();
+}
+
+/*
+ * seqam_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 670af18..4a6e0f2 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8772,6 +8772,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 65f3b98..fc309e2 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3277,7 +3277,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);
 
 	return newnode;
 }
@@ -3289,7 +3291,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 4c9b05e..258c09e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1542,7 +1542,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);
 
 	return true;
 }
@@ -1552,7 +1554,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 363c603..d4511e5 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"
@@ -3331,7 +3332,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;
 					$$ = (Node *)n;
 				}
@@ -3342,7 +3369,31 @@ AlterSeqStmt:
 				{
 					AlterSeqStmt *n = makeNode(AlterSeqStmt);
 					n->sequence = $3;
+					n->accessMethod = DEFAULT_SEQAM;
+					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;
 				}
@@ -3350,11 +3401,34 @@ AlterSeqStmt:
 				{
 					AlterSeqStmt *n = makeNode(AlterSeqStmt);
 					n->sequence = $5;
+					n->accessMethod = DEFAULT_SEQAM;
 					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; }
@@ -3413,7 +3487,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 19d19e5f..a16c9bb 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 c467f11..1f123f2 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -1043,10 +1043,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 b4cc6ad..ea5eb1a 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"
@@ -241,6 +242,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);
@@ -932,11 +934,14 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	else
 		relation->trigdesc = 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);
@@ -1370,6 +1375,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 index'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
@@ -4375,6 +4413,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 e9bdfea..2fddb27 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 538d027..a3e3d0d 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"
@@ -2663,6 +2664,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/include/access/reloptions.h b/src/include/access/reloptions.h
index 5a4664b..ef523b7 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;
@@ -270,6 +272,8 @@ extern bytea *default_reloptions(Datum reloptions, bool validate,
 extern bytea *heap_reloptions(char relkind, 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..61a1d1b
--- /dev/null
+++ b/src/include/access/seqam.h
@@ -0,0 +1,70 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqam.h
+ *	  Public header file for Sequence access method.
+ *
+ *
+ * Portions Copyright (c) 1996-2013, 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"
+
+/*
+ * We store a SeqTable item for every sequence we have touched in the current
+ * session.  This is needed to hold onto nextval/currval state.  (We can't
+ * rely on the relcache, since it's only, well, a cache, and may decide to
+ * discard entries.)
+ *
+ * XXX We use linear search to find pre-existing SeqTable entries.	This is
+ * good when only a small number of sequences are touched in a session, but
+ * would suck with many different sequences.  Perhaps use a hashtable someday.
+ */
+typedef struct SeqTableData
+{
+	struct SeqTableData *next;	/* link to next SeqTable object */
+	Oid			relid;			/* pg_class OID of this sequence */
+	Oid			filenode;		/* last seen relfilenode of this sequence */
+	LocalTransactionId lxid;	/* xact in which we last did a seq op */
+	bool		last_valid;		/* do we have a valid "last" value? */
+	int64		last;			/* value last returned by nextval */
+	int64		cached;			/* last value already cached for nextval */
+	/* 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		am_private;		/* private data of the SeqAm */
+} SeqTableData;
+
+typedef SeqTableData *SeqTable;
+
+extern char *default_seqam;
+
+Oid GetDefaultSeqAM(void);
+
+extern void sequence_alloc(Relation seqRelation, SeqTable seq_elem, Buffer buf, HeapTuple tup);
+extern void sequence_setval(Relation seqRelation, SeqTable seq_elem, Buffer buf, HeapTuple tup, int64 next, bool iscalled);
+
+
+extern void sequence_local_alloc(PG_FUNCTION_ARGS);
+extern void sequence_local_setval(PG_FUNCTION_ARGS);
+extern Datum sequence_local_options(PG_FUNCTION_ARGS);
+
+extern Oid get_seqam_oid(const char *sequencename, bool missing_ok);
+
+extern void log_sequence_tuple(Relation seqrel, HeapTuple tup, Page page);
+extern void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
+extern Form_pg_sequence read_seq_tuple(SeqTable elm, Relation rel,
+			   Buffer *buf, HeapTuple seqtuple);
+#endif   /* SEQAM_H */
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 4860e98..bb3c6e6 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -213,6 +213,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, 3480, on pg_seqam using btree(seqamname name_ops));
+#define SeqAmNameIndexId  3480
+DECLARE_UNIQUE_INDEX(pg_seqam_oid_index, 3481, on pg_seqam using btree(oid oid_ops));
+#define SeqAmOidIndexId  3481
+
 /* This following index is not used for a cache and is not unique */
 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
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ca4fc62..54d4e13 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4746,6 +4746,12 @@ DESCR("SP-GiST support for quad tree over range");
 DATA(insert OID = 3473 (  spg_range_quad_leaf_consistent	PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 16 "2281 2281" _null_ _null_ _null_ _null_  spg_range_quad_leaf_consistent _null_ _null_ _null_ ));
 DESCR("SP-GiST support for quad tree over range");
 
+DATA(insert OID = 3939 (  sequence_local_alloc	   PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ sequence_local_alloc _null_ _null_ _null_ ));
+DESCR("Local SequenceAM allocation");
+DATA(insert OID = 3940 (  sequence_local_setval	   PGNSP PGUID 12 1 0 0 0 f f f f t f s 2 0 2281 "2281 2281 2281 20 16" _null_ _null_ _null_ _null_ sequence_local_setval _null_ _null_ _null_ ));
+DESCR("Local SequenceAM setval");
+DATA(insert OID = 3936 (  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_ ));
diff --git a/src/include/catalog/pg_seqam.h b/src/include/catalog/pg_seqam.h
new file mode 100644
index 0000000..00a6f03
--- /dev/null
+++ b/src/include/catalog/pg_seqam.h
@@ -0,0 +1,70 @@
+/*-------------------------------------------------------------------------
+ *
+ * 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		seqamoptions;		/* parse AM-specific parameters */
+} 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						4
+#define Anum_pg_seqam_amname				1
+#define Anum_pg_seqam_amalloc				2
+#define Anum_pg_seqam_amsetval				3
+#define Anum_pg_seqam_amoptions				4
+
+/* ----------------
+ *		initial contents of pg_seqam
+ * ----------------
+ */
+
+DATA(insert OID = 3971 (  local		sequence_local_alloc sequence_local_setval sequence_local_options));
+DESCR("local sequence access method");
+#define LOCAL_SEQAM_OID 3971
+
+#define DEFAULT_SEQAM	""
+
+#endif   /* PG_SEQAM_H */
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index ffafe6c..9b4ac6e 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 e5235cb..89a1727 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1886,16 +1886,20 @@ 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) */
 } CreateSeqStmt;
 
 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 3e981b3..6e93258 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -376,6 +376,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 589c9a8..d930ac9 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;
 
 
@@ -123,23 +134,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
+	 * object).	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 */
@@ -150,7 +163,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 e41b3d2..9b6f434 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/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 57d614f..b8e822e 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -51,9 +51,11 @@ WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
        0::oid = ANY (p1.proargtypes) OR
        procost <= 0 OR
        CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END;
- oid | proname 
------+---------
-(0 rows)
+ oid  |        proname        
+------+-----------------------
+ 3939 | sequence_local_alloc
+ 3940 | sequence_local_setval
+(2 rows)
 
 -- prosrc should never be null or empty
 SELECT p1.oid, p1.proname
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index a62a3e3..fe6c3fe 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -122,6 +122,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 8fcb700..39e3e9d 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -171,9 +171,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');
@@ -189,9 +189,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 c725bba..e2ee303 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -117,6 +117,7 @@ SELECT table_name, column_name, is_updatable
  ro_view20  | log_cnt       | NO
  ro_view20  | is_cycled     | NO
  ro_view20  | is_called     | NO
+ ro_view20  | amdata        | NO
  ro_view21  | a             | NO
  ro_view21  | b             | NO
  ro_view21  | g             | NO
@@ -140,7 +141,7 @@ SELECT table_name, column_name, is_updatable
  rw_view16  | a             | YES
  rw_view16  | b             | YES
  rw_view16  | aa            | YES
-(48 rows)
+(49 rows)
 
 -- Read-only views
 DELETE FROM ro_view1;
diff --git a/src/test/regress/sql/namespace.sql b/src/test/regress/sql/namespace.sql
index 879b6c3..2bb9134 100644
--- a/src/test/regress/sql/namespace.sql
+++ b/src/test/regress/sql/namespace.sql
@@ -1,7 +1,6 @@
 --
 -- Regression tests for schemas (namespaces)
 --
-
 CREATE SCHEMA test_schema_1
        CREATE UNIQUE INDEX abc_a_idx ON abc (a)
 
