>From 366f7187b69eaba69514f46aa594ba09e84bbc0e Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmodos@pjmodos.net>
Date: Wed, 2 Mar 2016 16:15:33 +0100
Subject: [PATCH 1/2] seqam

---
 doc/src/sgml/filelist.sgml                    |    1 +
 doc/src/sgml/postgres.sgml                    |    1 +
 doc/src/sgml/ref/alter_sequence.sgml          |   55 +
 doc/src/sgml/ref/create_access_method.sgml    |    9 +-
 doc/src/sgml/ref/create_sequence.sgml         |   25 +
 doc/src/sgml/seqam.sgml                       |  312 +++++
 src/backend/access/Makefile                   |    4 +-
 src/backend/access/common/reloptions.c        |   13 +-
 src/backend/access/sequence/Makefile          |   17 +
 src/backend/access/sequence/seqamapi.c        |  191 ++++
 src/backend/access/sequence/seqlocal.c        |  414 +++++++
 src/backend/bootstrap/bootparse.y             |    1 +
 src/backend/catalog/heap.c                    |   17 +-
 src/backend/catalog/objectaddress.c           |    1 +
 src/backend/catalog/toasting.c                |    1 +
 src/backend/commands/amcmds.c                 |   38 +-
 src/backend/commands/cluster.c                |    1 +
 src/backend/commands/createas.c               |    3 +-
 src/backend/commands/indexcmds.c              |    2 +-
 src/backend/commands/sequence.c               | 1515 +++++++++++++++----------
 src/backend/commands/tablecmds.c              |   49 +-
 src/backend/commands/typecmds.c               |    3 +-
 src/backend/commands/view.c                   |    3 +-
 src/backend/nodes/copyfuncs.c                 |    4 +
 src/backend/nodes/equalfuncs.c                |    4 +
 src/backend/parser/gram.y                     |   91 +-
 src/backend/parser/parse_utilcmd.c            |    3 +
 src/backend/tcop/utility.c                    |    6 +-
 src/backend/utils/adt/pseudotypes.c           |   25 +
 src/backend/utils/cache/relcache.c            |   53 +-
 src/backend/utils/misc/guc.c                  |    1 +
 src/bin/pg_dump/pg_dump.c                     |  132 ++-
 src/bin/pg_dump/pg_dump.h                     |    1 +
 src/bin/psql/describe.c                       |  112 +-
 src/include/access/reloptions.h               |    2 +-
 src/include/access/seqamapi.h                 |  109 ++
 src/include/catalog/heap.h                    |    1 +
 src/include/catalog/pg_am.h                   |    5 +
 src/include/catalog/pg_proc.h                 |   19 +
 src/include/catalog/pg_type.h                 |    7 +
 src/include/commands/defrem.h                 |    1 +
 src/include/commands/sequence.h               |   30 +-
 src/include/commands/tablecmds.h              |    2 +-
 src/include/nodes/nodes.h                     |    1 +
 src/include/nodes/parsenodes.h                |    8 +-
 src/include/utils/builtins.h                  |    2 +
 src/include/utils/rel.h                       |    8 +-
 src/test/regress/expected/create_am.out       |   19 +
 src/test/regress/expected/create_view.out     |    5 +-
 src/test/regress/expected/opr_sanity.out      |    4 +-
 src/test/regress/expected/sequence.out        |   35 +-
 src/test/regress/expected/updatable_views.out |   95 +-
 src/test/regress/sql/create_am.sql            |   16 +
 src/test/regress/sql/create_view.sql          |    5 +-
 src/test/regress/sql/opr_sanity.sql           |    4 +-
 src/test/regress/sql/sequence.sql             |   10 +-
 56 files changed, 2712 insertions(+), 784 deletions(-)
 create mode 100644 doc/src/sgml/seqam.sgml
 create mode 100644 src/backend/access/sequence/Makefile
 create mode 100644 src/backend/access/sequence/seqamapi.c
 create mode 100644 src/backend/access/sequence/seqlocal.c
 create mode 100644 src/include/access/seqamapi.h

diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 30adece..fd355dc 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -90,6 +90,7 @@
 <!ENTITY brin       SYSTEM "brin.sgml">
 <!ENTITY planstats    SYSTEM "planstats.sgml">
 <!ENTITY indexam    SYSTEM "indexam.sgml">
+<!ENTITY seqam      SYSTEM "seqam.sgml">
 <!ENTITY nls        SYSTEM "nls.sgml">
 <!ENTITY plhandler  SYSTEM "plhandler.sgml">
 <!ENTITY fdwhandler SYSTEM "fdwhandler.sgml">
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 7e82cdc..d37058a 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -251,6 +251,7 @@
   &spgist;
   &gin;
   &brin;
+  &seqam;
   &storage;
   &bki;
   &planstats;
diff --git a/doc/src/sgml/ref/alter_sequence.sgml b/doc/src/sgml/ref/alter_sequence.sgml
index 47d3c82..ba2c3d9 100644
--- a/doc/src/sgml/ref/alter_sequence.sgml
+++ b/doc/src/sgml/ref/alter_sequence.sgml
@@ -29,9 +29,15 @@ ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [
     [ RESTART [ [ WITH ] <replaceable class="parameter">restart</replaceable> ] ]
     [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
     [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ]
+    [ USING <replaceable class="parameter">access_method</replaceable> [ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] ) ] ]
 ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable class="PARAMETER">new_owner</replaceable> | CURRENT_USER | SESSION_USER }
 ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
 ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
+ALTER SEQUENCE [ IF EXISTS ] <replaceable class="PARAMETER">action</replaceable> [, ... ]
+
+<phrase>where <replaceable class="PARAMETER">action</replaceable> is one of:</phrase>
+    SET ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] )
+    RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )
 </synopsis>
  </refsynopsisdiv>
 
@@ -221,6 +227,24 @@ ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> S
    </varlistentry>
 
    <varlistentry>
+    <term><literal>USING</literal> <replaceable class="parameter">access_method</replaceable></term>
+    <listitem>
+     <para>
+      The <literal>USING</literal> option specifies which sequence access
+      method will be used when generating the sequence numbers.
+     </para>
+     <para>
+      When the <literal>RESTART WITH <replaceable
+      class="parameter">restart</replaceable></literal> parameter is also
+      given, it will be used as a starting value for the new access method.
+      Otherwise the <function>nextval</> function will be called with the old
+      access method and the result will be used as start value for the new
+      access method.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="PARAMETER">new_owner</replaceable></term>
     <listitem>
      <para>
@@ -247,6 +271,37 @@ ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> S
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term><literal>SET ( <replaceable class="PARAMETER">storage_parameter</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] )</literal></term>
+    <listitem>
+     <para>
+      This clause changes one or more storage parameters for the sequence
+      access method.
+     </para>
+
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )</literal></term>
+    <listitem>
+     <para>
+      This clause resets one or more storage parameters to their defaults.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] )</literal></term>
+    <listitem>
+     <para>
+      This clause specifies optional storage parameters for the new sequence
+      access method.
+     </para>
+
+    </listitem>
+   </varlistentry>
+
     </variablelist>
    </para>
   </refsect1>
diff --git a/doc/src/sgml/ref/create_access_method.sgml b/doc/src/sgml/ref/create_access_method.sgml
index 3c091f8..8676a84 100644
--- a/doc/src/sgml/ref/create_access_method.sgml
+++ b/doc/src/sgml/ref/create_access_method.sgml
@@ -61,7 +61,8 @@ CREATE ACCESS METHOD <replaceable class="parameter">name</replaceable>
     <listitem>
      <para>
       This clause specifies type of access method to define.
-      Only <literal>INDEX</literal> is supported at present.
+      Supported values are <literal>INDEX</literal> for index access methods
+      and <literal>SEQUENCE</literal> for sequence access methods.
      </para>
     </listitem>
    </varlistentry>
@@ -75,7 +76,9 @@ CREATE ACCESS METHOD <replaceable class="parameter">name</replaceable>
       of access method to the core.  The handler function must take single
       argument of type <type>internal</>, and its return type depends on the
       type of access method; for <literal>INDEX</literal> access methods, it
-      must be <type>index_am_handler</type>.
+      must be <type>index_am_handler</type> and for
+      <literal>SEQUENCE</literal> access methods it must be
+      <type>sequence_am_handler</type>.
      </para>
 
      <para>
@@ -114,6 +117,8 @@ CREATE ACCESS METHOD heptree TYPE INDEX HANDLER heptree_handler;
    <member><xref linkend="sql-drop-access-method"></member>
    <member><xref linkend="sql-createopclass"></member>
    <member><xref linkend="sql-createopfamily"></member>
+   <member><xref linkend="index-api"> </member>
+   <member><xref linkend="seqam"></member>
   </simplelist>
  </refsect1>
 
diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml
index 9e364ff..85840ff 100644
--- a/doc/src/sgml/ref/create_sequence.sgml
+++ b/doc/src/sgml/ref/create_sequence.sgml
@@ -25,6 +25,8 @@ CREATE [ TEMPORARY | TEMP ] SEQUENCE [ IF NOT EXISTS ] <replaceable class="param
     [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
     [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
     [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ]
+    [ USING <replaceable class="parameter">access_method</replaceable> ]
+    [ WITH ( <replaceable class="parameter">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] ) ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -223,6 +225,29 @@ SELECT * FROM <replaceable>name</replaceable>;
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><literal>USING</literal> <replaceable class="parameter">access_method</replaceable></term>
+    <listitem>
+     <para>
+      The <literal>USING</literal> option specifies which sequence access
+      method will be used when generating the sequence numbers. The default
+      is <literal>"local"</>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] )</literal></term>
+    <listitem>
+     <para>
+      This clause specifies optional storage parameters for a sequence access
+      method.
+     </para>
+
+    </listitem>
+   </varlistentry>
+
   </variablelist>
  </refsect1>
 
diff --git a/doc/src/sgml/seqam.sgml b/doc/src/sgml/seqam.sgml
new file mode 100644
index 0000000..5faeae3
--- /dev/null
+++ b/doc/src/sgml/seqam.sgml
@@ -0,0 +1,312 @@
+<!-- doc/src/sgml/seqam.sgml -->
+
+<chapter id="seqam">
+ <title>Sequence Access Method Interface Definition</title>
+
+  <para>
+   This chapter describes the interface for writing sequence access methods.
+  </para>
+
+  <para>
+   The sequence access method defines behavior of a sequence which is using it.
+   Mainly how the new values are generated. Each sequence can have different
+   access method in order to behave in a way that makes most sense in the
+   application context.
+  </para>
+
+ <sect1 id="seqam-catalog">
+  <title>Catalog Entries for Sequence Access Method</title>
+
+  <para>
+   Each sequence access method is described by a row in the
+   <structname>pg_am</structname> system catalog (see
+   <xref linkend="catalog-pg-am">).
+  </para>
+ </sect1>
+
+ <sect1 id="seqam-functions">
+  <title>Sequence Access Method Functions</title>
+
+  <para>
+   The SQL interface of the sequence access method consists of a handler
+   function which has to return special pseudo-type
+   <type>sequence_handler</type>. This function must be written in a compiled
+   language such as C, using the version-1 interface. For details on C
+   language calling conventions and dynamic loading, see
+   <xref linkend="xfunc-c">.
+  </para>
+
+  <para>
+   The actual C structure returned by the handler function is following:
+<programlisting>
+typedef struct SeqAmRoutine
+{
+    NodeTag        type;
+
+    /* Custom datatype used for storing state of the sequence by the AM */
+    Oid            StateTypeOid;
+
+    /* Function for parsing reloptions */
+    ParseRelOptions_function    amoptions;
+
+    /* Initialization */
+    SeqAMInit_function          Init;
+
+    /* nextval handler */
+    SeqAMAlloc_function         Alloc;
+
+    /* State manipulation functions */
+    SeqAMSetval_function        Setval;
+    SeqAMGetState_function      GetState;
+    SeqAMSetState_function      SetState;
+} SeqAmRoutine;
+</programlisting>
+  </para>
+
+  <para>
+   These are the functions implemented by the sequence access method.
+  </para>
+
+  <para>
+   The functions defining a sequence access method are:
+  </para>
+
+  <para>
+<programlisting>
+Datum
+SeqAMInit (Relation seqrel, Form_pg_sequence seq, int64 restart_value,
+           bool restart_requested, bool is_init)
+</programlisting>
+   Initialize the sequence's internal state. This function is called both
+   when a new sequence is created, when the <command>ALTER SEQUENCE</> command
+   is called for an existing sequence or by the
+   <command>TRUNCATE RESTART IDENTITY</> command.
+  </para>
+
+  <para>
+   The <literal>seqrel</> points to relcache record representing the
+   <link linkend="catalog-pg-class"><structname>pg_class</structname></link>
+   tuple tuple of the sequence.
+   The <literal>seq</> is in-memory version of the
+   <structname>pg_sequence</structname> tuple itself. The
+   <literal>restart_value</> is value the sequence should start from and the
+   <literal>restart_requested</> gives indication if the
+   <literal>restart_value</> should indeed be used. Finally <literal>is_init</>
+   is <literal>true</> when this is new sequence being created or when the
+   access method of a sequence has been changed, otherwise it's
+   <literal>false</>.
+
+   to the options in the <command>CREATE SEQUENCE</> or
+   <command>ALTER SEQUENCE</> statement.
+   <literal>reloptions</> contains parsed reloptions passed to the
+   <command>CREATE SEQUENCE</> or <command>ALTER SEQUENCE</> statements.
+   The <literal>values</> and <literal>nulls</> describe new tuple for the
+   <structname>pg_sequence</structname> tuple which this function can update
+   as needed.
+  </para>
+
+  <para>
+   This function should return the Datum of a state of the sequence. The type
+   of the Datum is the <structname>StateTypeOid</structname> type.
+  </para>
+
+  <para>
+<programlisting>
+bytea *
+ParseRelOptions (Datum reloptions, bool validate)
+</programlisting>
+   Parse and validate the reloptions array for an sequence.
+   <parameter>reloptions</> is a <type>text</> array containing entries of the
+   form <replaceable>name</><literal>=</><replaceable>value</>.
+   The function should construct a <type>bytea</> value.
+   When <parameter>validate</> is true, the function should report a suitable
+   error message if any of the options are unrecognized or have invalid
+   values; when <parameter>validate</> is false, invalid entries should be
+   silently ignored.  (<parameter>validate</> is false when loading options
+   already stored in <structname>pg_catalog</>; an invalid entry could only
+   be found if the access method has changed its rules for options, and in
+   that case ignoring obsolete entries is appropriate.)
+   It is OK to return NULL if default behavior is wanted.
+  </para>
+
+  <para>
+<programlisting>
+int64
+SeqAMAlloc (Relation seqrel, SequenceHandle *seqh, int64 nrequested,
+            int64 *last)
+</programlisting>
+   Allocate new sequence value(s). The <literal>nrequested</> specifies how
+   many new values should be allocated by this call. Return value is the next
+   allocated value and <literal>last</> should be set to last allocated value.
+  </para>
+
+  <para>
+<programlisting>
+void SeqAMSetval (Relation seqrel, SequenceHandle *seqh, int64 new_value)
+</programlisting>
+   Set the current sequence value the the <literal>new_value</>.
+  </para>
+
+  <para>
+<programlisting>
+Datum SeqAMGetState (Relation seqrel, SequenceHandle *seqh)
+</programlisting>
+   Dump the current state of the sequence. The return value is the Datum of
+   a <structname>StateTypeOid</structname>. This interface is mainly
+   used by <command>pg_dump</command>.
+  </para>
+
+  <para>
+<programlisting>
+void SeqAMSetState (Relation seqrel, SequenceHandle *seqh, Datum amstate)
+</programlisting>
+   Restore state of the sequence based on amstate which is Datum of a
+   <structname>StateTypeOid</structname> type.
+   This interface is mainly used by <command>pg_dump</command>.
+  </para>
+
+ </sect1>
+
+ <sect1 id="seqam-storage">
+  <title>Sequence Access Method Storage API</title>
+
+  <para>
+   To store the current state of the sequence, the backend provides the
+   following helper functions which the sequence access method can use:
+  </para>
+
+  <para>
+<programlisting>
+void
+sequence_open(Oid seqrelid, SequenceHandle *seqh)
+</programlisting>
+   Open sequence with given <literal>relid</>. The <literal>seqh</> is
+   output parameter which will be set to the sequence handle.
+  </para>
+
+  <para>
+<programlisting>
+void
+sequence_close (SequenceHandle *seqh)
+</programlisting>
+   Release and close the opened sequence.
+  </para>
+
+  <para>
+<programlisting>
+Form_pg_sequence
+(SequenceHandle *seqh)
+</programlisting>
+   Reads and locks the sequence tuple for processing by the access method.
+   Returns the whole pg_sequence tuple as the
+   <structname>Form_pg_sequence</structname> structure.
+   The tuple should be released by calling <function>sequence_release_tuple</>.
+  </para>
+
+  <para>
+<programlisting>
+Datum
+sequence_read_state(SequenceHandle *seqh)
+</programlisting>
+   Reads and locks the sequence tuple for processing by the access method.
+   Returns just the sequence access method specific state Datum.
+   The tuple should be released by calling <function>sequence_release_tuple</>.
+  </para>
+
+  <para>
+<programlisting>
+void
+sequence_start_update(SequenceHandle *seqh, bool do_wal)
+</programlisting>
+   Start the sequence update. The <literal>do_wal</> gives hint if at least
+   one of subsequent <function>sequence_apply_update()</> calls will be with
+   <literal>do_wal = true</>.
+</para>
+
+  <para>
+<programlisting>
+void
+sequence_save_state(SequenceHandle *seqh, Datum seqstate, bool dowal)
+</programlisting>
+   Save the modified sequence state tuple indicating if the change should be
+   WAL logged as well as saved to the catalog.
+  </para>
+
+  <para>
+<programlisting>
+void
+sequence_finish_update(SequenceHandle *seqh)
+</programlisting>
+   Finish the sequence update.
+  </para>
+
+  <para>
+  To update the sequence tuple you have to call all three above functions in
+  order to be sure the update is applied in error safe manner. The
+  <function>sequence_save_update()</> can be called multiple times between
+  single pair of <function>sequence_start_update()</> and
+  <function>sequence_finish_update()</> calls. Update function cannot be called
+  if the tuple was already released by the
+  <function>sequence_release_tuple()</> function.
+  </para>
+
+  <para>
+<programlisting>
+void
+sequence_release_tuple(SequenceHandle *seqh)
+</programlisting>
+   Release the tuple read and locked by <function>sequence_read_options</>
+   and/or added by <function>sequence_read_state</>.
+  </para>
+
+ </sect1>
+
+ <sect1 id="seqam-utility">
+  <title>Sequence Access Method Utility Functions</title>
+
+  <para>
+   Additional utility functions which can be useful when writing sequence
+   access methods:
+  </para>
+
+  <para>
+<programlisting>
+bool
+sequence_needs_wal(SequenceHandle *seqh)
+</programlisting>
+   Returns <literal>true</> if the sequence tuple was last saved before last
+   checkpoint. This can be help when deciding what to set <literal>do_wal</>
+   to when calling <function>sequence_save_update</>.
+  </para>
+
+  <para>
+<programlisting>
+int64
+sequence_increment(Relation seqrel, int64 *value, int64 incnum,
+                   int64 minv, int64 maxv, int64 incby,
+                   bool is_cycled, bool report_errors)
+</programlisting>
+   Helper function to increment value of a sequence, correctly handling
+   sequence options like min value, max value, increment value and cycling of
+   the sequence value. The <literal>value</> is pointer to current value which
+   should be incremented, <literal>incnum</> specifies how much should the
+   value be incremented, the rest of the options should be set to values
+   specified by the sequence's <structname>pg_sequence</structname> tuple.
+   Returns by how much was the value increased.
+  </para>
+
+  <para>
+<programlisting>
+void
+sequence_check_range (int64 value, int64 min_value,
+                      int64 max_value, const char *valname)
+</programlisting>
+   Checks if the <literal>value</> is between <literal>min_value</>
+   and <literal>max_value</> and raises standard error message if it's not.
+   The <literal>valname</> is used as the name of the wrong value in the error
+   message.
+  </para>
+
+ </sect1>
+
+</chapter>
diff --git a/src/backend/access/Makefile b/src/backend/access/Makefile
index bd93a6a..223403d 100644
--- a/src/backend/access/Makefile
+++ b/src/backend/access/Makefile
@@ -8,7 +8,7 @@ subdir = src/backend/access
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-SUBDIRS	    = brin common gin gist hash heap index nbtree rmgrdesc spgist \
-			  tablesample transam
+SUBDIRS	    = brin common gin gist hash heap index nbtree rmgrdesc sequence \
+			  spgist tablesample transam
 
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index ea0755a..bb368d2 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -888,8 +888,8 @@ untransformRelOptions(Datum options)
  * instead.
  *
  * tupdesc is pg_class' tuple descriptor.  amoptions is a pointer to the index
- * AM's options parser function in the case of a tuple corresponding to an
- * index, or NULL otherwise.
+ * or sequence AM's options parser function in the case of a tuple corresponding
+ * to an index or sequence respectively, or NULL otherwise.
  */
 bytea *
 extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
@@ -921,7 +921,8 @@ extractRelOptions(HeapTuple tuple, TupleDesc tupdesc,
 			options = view_reloptions(datum, false);
 			break;
 		case RELKIND_INDEX:
-			options = index_reloptions(amoptions, datum, false);
+		case RELKIND_SEQUENCE:
+			options = am_reloptions(amoptions, datum, false);
 			break;
 		case RELKIND_FOREIGN_TABLE:
 			options = NULL;
@@ -1374,14 +1375,14 @@ heap_reloptions(char relkind, Datum reloptions, bool validate)
 
 
 /*
- * Parse options for indexes.
+ * Parse options for access methods.
  *
- *	amoptions	index AM's option parser function
+ *	amoptions	AM's option parser function
  *	reloptions	options as text[] datum
  *	validate	error flag
  */
 bytea *
-index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
+am_reloptions(amoptions_function amoptions, Datum reloptions, bool validate)
 {
 	Assert(amoptions != NULL);
 
diff --git a/src/backend/access/sequence/Makefile b/src/backend/access/sequence/Makefile
new file mode 100644
index 0000000..1784799
--- /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 = seqamapi.o seqlocal.o
+
+include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/access/sequence/seqamapi.c b/src/backend/access/sequence/seqamapi.c
new file mode 100644
index 0000000..ef8e7a4
--- /dev/null
+++ b/src/backend/access/sequence/seqamapi.c
@@ -0,0 +1,191 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqamapi.c
+ *	  general sequence access method routines
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/access/sequence/seqamapi.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 _init 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, amstate.
+ *
+ * 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_am.
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "access/relscan.h"
+#include "access/seqamapi.h"
+#include "access/transam.h"
+#include "access/xact.h"
+#include "catalog/pg_am.h"
+#include "catalog/pg_type.h"
+#include "utils/builtins.h"
+#include "utils/guc.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+#include "utils/syscache.h"
+
+
+/*
+ * GetSeqAmRoutine - call the specified access method handler routine
+ * to get its SeqAmRoutine struct.
+ */
+SeqAmRoutine *
+GetSeqAmRoutine(Oid amhandler)
+{
+	Datum			datum;
+	SeqAmRoutine   *routine;
+
+	datum = OidFunctionCall0(amhandler);
+	routine = (SeqAmRoutine *) DatumGetPointer(datum);
+
+	if (routine == NULL || !IsA(routine, SeqAmRoutine))
+		elog(ERROR, "sequence access method handler function %u did not return an SeqAmRoutine struct",
+			 amhandler);
+
+	return routine;
+}
+
+/*
+ * GetSeqAmRoutineByAMId - look up the handler of the sequence access method
+ * for the given OID, and retrieve its SeqAmRoutine struct.
+ */
+SeqAmRoutine *
+GetSeqAmRoutineByAMId(Oid amoid)
+{
+	HeapTuple		tuple;
+	regproc			amhandler;
+	Form_pg_am		amform;
+
+	/* Get handler function OID for the access method */
+	tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for access method %u",
+			 amoid);
+	amform = (Form_pg_am) GETSTRUCT(tuple);
+	amhandler = amform->amhandler;
+
+	/* Complain if handler OID is invalid */
+	if (!RegProcedureIsValid(amhandler))
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("sequence access method \"%s\" does not have a handler",
+						NameStr(amform->amname))));
+	ReleaseSysCache(tuple);
+
+	/* And finally, call the handler function. */
+	return GetSeqAmRoutine(amhandler);
+}
+
+/*
+ * GetSeqAmRoutineForRelation - look up the handler of the sequence access
+ * method for the given sequence Relation.
+ */
+SeqAmRoutine *
+GetSeqAmRoutineForRelation(Relation relation)
+{
+	SeqAmRoutine *seqam;
+	SeqAmRoutine *cseqam;
+
+	if (relation->rd_seqamroutine == NULL)
+	{
+		if (!OidIsValid(relation->rd_rel->relam))
+		{
+			char *relname = quote_qualified_identifier(get_namespace_name(RelationGetNamespace(relation)),
+													   RelationGetRelationName(relation));
+			elog(ERROR, "relation %s isn't sequence", relname);
+		}
+
+		seqam = GetSeqAmRoutineByAMId(relation->rd_rel->relam);
+		/* Save the data for later reuse in CacheMemoryContext */
+		cseqam = (SeqAmRoutine *) MemoryContextAlloc(CacheMemoryContext,
+												   sizeof(SeqAmRoutine));
+		memcpy(cseqam, seqam, sizeof(SeqAmRoutine));
+		relation->rd_seqamroutine = cseqam;
+	}
+
+	return relation->rd_seqamroutine;
+}
+
+/*
+ * ValidateSeqAmRoutine - to sanity check for the SeqAmRoutine returned by a
+ * handler.
+ *
+ * At the moment we only check that the StateTypeOid is valid type oid and that
+ * the type it points to is fixed width and will fit into the sequence page.
+ */
+void
+ValidateSeqAmRoutine(SeqAmRoutine *routine)
+{
+#define MAX_SEQAM_STATE_LEN \
+	MaxHeapTupleSize - MinHeapTupleSize - MAXALIGN(sizeof(FormData_pg_sequence))
+
+	Oid	stattypeoid = routine->StateTypeOid;
+
+	if (!get_typisdefined(stattypeoid))
+		ereport(ERROR,
+				(errmsg("type with OID %u does not exist",
+						stattypeoid)));
+
+	if (TypeIsToastable(stattypeoid))
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("sequence access method state data type \"%s\" must not be toastable",
+						format_type_be(stattypeoid))));
+
+	if (get_typlen(stattypeoid) >= MAX_SEQAM_STATE_LEN)
+		ereport(ERROR,
+				(errcode(ERRCODE_DATATYPE_MISMATCH),
+				 errmsg("sequence access method state data type \"%s\" exceeds maximum allowed length (%lu)",
+						format_type_be(stattypeoid), MAX_SEQAM_STATE_LEN)));
+
+}
diff --git a/src/backend/access/sequence/seqlocal.c b/src/backend/access/sequence/seqlocal.c
new file mode 100644
index 0000000..03ac01f
--- /dev/null
+++ b/src/backend/access/sequence/seqlocal.c
@@ -0,0 +1,414 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqlocal.c
+ *	  Local sequence access manager
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/access/sequence/seqlocal.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "access/htup_details.h"
+#include "access/reloptions.h"
+#include "access/seqamapi.h"
+#include "access/xact.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "utils/builtins.h"
+#include "utils/int8.h"
+#include "utils/rel.h"
+#include "utils/typcache.h"
+
+typedef struct LocalSequence
+{
+	FormData_pg_sequence	seq;
+	LocalSequenceState		state;
+} LocalSequence;
+
+/*
+ * We don't want to log each fetching of a value from a sequence,
+ * so we pre-log a few fetches in advance. In the event of
+ * crash we can lose (skip over) as many values as we pre-logged.
+ */
+#define SEQ_LOG_VALS	32
+
+static bytea *seqam_local_reloptions(Datum reloptions, bool validate);
+static Datum seqam_local_init(Relation seqrel, Form_pg_sequence seq,
+							  int64 restart_value, bool restart_requested,
+							  bool is_init);
+static int64 seqam_local_alloc(Relation seqrel, SequenceHandle *seqh,
+							   int64 nrequested, int64 *last);
+static void seqam_local_setval(Relation seqrel, SequenceHandle *seqh,
+							   int64 new_value);
+static Datum seqam_local_get_state(Relation seqrel, SequenceHandle *seqh);
+static void seqam_local_set_state(Relation seqrel, SequenceHandle *seqh,
+								  Datum amstate);
+
+static char *
+seqam_local_state_get_part(StringInfo buf, char *ptr, bool *found)
+{
+	*found = false;
+
+	resetStringInfo(buf);
+
+	while (*ptr != ',' && *ptr != ')')
+	{
+		char		ch = *ptr++;
+
+		if (ch == '\0')
+		{
+			*found = false;
+			return ptr;
+		}
+
+		appendStringInfoChar(buf, ch);
+
+		if (!*found)
+			*found = true;
+	}
+
+	return ptr;
+}
+
+Datum
+seqam_local_state_in(PG_FUNCTION_ARGS)
+{
+	char	   *state_str = PG_GETARG_CSTRING(0);
+	char	   *ptr;
+	Datum		d;
+	bool		found;
+	StringInfoData		buf;
+	LocalSequenceState *state = palloc(sizeof(LocalSequenceState));
+
+	ptr = state_str;
+	while (*ptr && isspace((unsigned char) *ptr))
+		ptr++;
+
+	if (*ptr != '(')
+		goto malformed;
+	ptr++;
+
+	initStringInfo(&buf);
+
+	/* last_value is required */
+	ptr = seqam_local_state_get_part(&buf, ptr, &found);
+	if (!found)
+		goto malformed;
+	d = DirectFunctionCall1(int8in, CStringGetDatum(buf.data));
+	state->last_value = DatumGetInt64(d);
+	if (*ptr == ',')
+		ptr++;
+
+	/* is_called is optional */
+	ptr = seqam_local_state_get_part(&buf, ptr, &found);
+	if (found)
+	{
+		d = DirectFunctionCall1(boolin, CStringGetDatum(buf.data));
+		state->is_called = DatumGetBool(d);
+		if (*ptr == ',')
+			ptr++;
+	}
+	else
+		state->is_called = true;
+
+	/* log_cnt is optional */
+	ptr = seqam_local_state_get_part(&buf, ptr, &found);
+	if (found)
+	{
+		d = DirectFunctionCall1(int4in, CStringGetDatum(buf.data));
+		state->log_cnt = DatumGetInt32(d);
+		if (*ptr == ',')
+			ptr++;
+	}
+	else
+		state->log_cnt = 0;
+
+	if (*ptr != ')' || *(++ptr) != '\0')
+		goto malformed;
+
+	PG_RETURN_POINTER(state);
+
+malformed:
+	ereport(ERROR,
+			(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+			 errmsg("malformed seqam_local_state literal: \"%s\"",
+					state_str)));
+}
+
+Datum
+seqam_local_state_out(PG_FUNCTION_ARGS)
+{
+	LocalSequenceState *state = (LocalSequenceState *) PG_GETARG_POINTER(0);
+	StringInfoData		buf;
+
+	initStringInfo(&buf);
+
+	appendStringInfo(&buf, "("INT64_FORMAT",%s,%d)",
+					 state->last_value, state->is_called ? "t" : "f",
+					 state->log_cnt);
+
+	PG_RETURN_CSTRING(buf.data);
+}
+
+/*
+ * Handler function for the local sequence access method.
+ */
+Datum
+seqam_local_handler(PG_FUNCTION_ARGS)
+{
+	SeqAmRoutine *seqam = makeNode(SeqAmRoutine);
+
+	seqam->StateTypeOid = SEQAMLOCALSTATEOID;
+	seqam->amoptions = seqam_local_reloptions;
+	seqam->Init = seqam_local_init;
+	seqam->Alloc = seqam_local_alloc;
+	seqam->Setval = seqam_local_setval;
+	seqam->GetState = seqam_local_get_state;
+	seqam->SetState = seqam_local_set_state;
+
+	PG_RETURN_POINTER(seqam);
+}
+
+/*
+ * seqam_local_reloptions()
+ *
+ * Parse and verify the reloptions of a local sequence.
+ */
+static bytea *
+seqam_local_reloptions(Datum reloptions, bool validate)
+{
+	if (validate && PointerIsValid(DatumGetPointer(reloptions)))
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("local sequence does not accept any storage parameters")));
+
+	return NULL;
+}
+
+/*
+ * seqam_local_init()
+ *
+ * Initialize local sequence
+ */
+static Datum
+seqam_local_init(Relation seqrel, Form_pg_sequence seq, int64 restart_value,
+				 bool restart_requested, bool is_init)
+{
+	LocalSequenceState	   *seqstate;
+
+	if (is_init)
+		seqstate = palloc0(sizeof(LocalSequenceState));
+	else
+		seqstate = &((LocalSequence *) seq)->state;
+
+	/*
+	 * If this is a new sequence or RESTART was provided in ALTER we should
+	 * reset our state to that new starting point.
+	 */
+	if (is_init || restart_requested)
+	{
+		seqstate->last_value = restart_value;
+		seqstate->is_called = false;
+	}
+
+	seqstate->log_cnt = 0;
+
+	return PointerGetDatum(seqstate);
+}
+
+/*
+ * seqam_local_alloc()
+ *
+ * Allocate a new range of values for a local sequence.
+ */
+static int64
+seqam_local_alloc(Relation seqrel, SequenceHandle *seqh, int64 nrequested,
+				  int64 *last)
+{
+	int64		incby,
+				maxv,
+				minv,
+				log,
+				fetch,
+				result,
+				next,
+				rescnt = 0;
+	bool		is_cycled,
+				is_called,
+				logit = false;
+	Form_pg_sequence	seq;
+	LocalSequenceState *localseq;
+
+	seq = sequence_read_options(seqh);
+	localseq = &((LocalSequence *) seq)->state;
+
+	next = result = localseq->last_value;
+	incby = seq->increment_by;
+	maxv = seq->max_value;
+	minv = seq->min_value;
+	is_cycled = seq->is_cycled;
+	fetch = nrequested;
+	log = localseq->log_cnt;
+	is_called = localseq->is_called;
+
+	/* We are returning last_value if not is_called so fetch one less value. */
+	if (!is_called)
+	{
+		nrequested--;
+		fetch--;
+	}
+
+	/*
+	 * Decide whether we should emit a WAL log record.  If so, force up the
+	 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
+	 * cache.  (These will then be usable without logging.)
+	 *
+	 * If this is the first nextval after a checkpoint, we must force a new
+	 * WAL record to be written anyway, else replay starting from the
+	 * checkpoint would fail to advance the sequence past the logged values.
+	 * In this case we may as well fetch extra values.
+	 */
+	if (log < fetch || !is_called)
+	{
+		/* Forced log to satisfy local demand for values. */
+		fetch = log = fetch + SEQ_LOG_VALS;
+		logit = true;
+	}
+	else if (sequence_needs_wal(seqh))
+	{
+		fetch = log = fetch + SEQ_LOG_VALS;
+		logit = true;
+	}
+
+	/* Fetch new result value if is_called. */
+	if (is_called)
+	{
+		rescnt += sequence_increment(seqrel, &next, 1, minv, maxv, incby,
+									 is_cycled, true);
+		result = next;
+	}
+
+	/* Fetch as many values as was requested by backend. */
+	if (rescnt < nrequested)
+		rescnt += sequence_increment(seqrel, &next, nrequested - rescnt, minv,
+									 maxv, incby, is_cycled, false);
+
+	/* Last value available for calling backend. */
+	*last = next;
+	/* Values we made available to calling backend can't be counted as cached. */
+	log -= rescnt;
+
+	/* We might need to fetch even more values for our own caching. */
+	if (rescnt < fetch)
+		rescnt += sequence_increment(seqrel, &next, fetch - rescnt, minv,
+									 maxv, incby, is_cycled, false);
+
+	fetch -= rescnt;
+	log -= fetch;				/* adjust for any unfetched numbers */
+	Assert(log >= 0);
+
+	/*
+	 * Log our cached data.
+	 */
+	localseq->last_value = *last;
+	localseq->log_cnt = log;
+	localseq->is_called = true;
+
+	sequence_start_update(seqh, logit);
+
+	if (logit)
+	{
+		localseq->last_value = next;
+		localseq->log_cnt = 0;
+		localseq->is_called = true;
+
+		sequence_save_state(seqh, PointerGetDatum(localseq), true);
+	}
+
+	localseq->last_value = *last;
+	localseq->log_cnt = log;
+	localseq->is_called = true;
+
+	sequence_save_state(seqh, PointerGetDatum(localseq), false);
+
+	sequence_finish_update(seqh);
+
+	return result;
+}
+
+/*
+ * seqam_local_setval()
+ *
+ * Set value of a local sequence
+ */
+static void
+seqam_local_setval(Relation seqrel, SequenceHandle *seqh, int64 new_value)
+{
+	Datum				amstate;
+	LocalSequenceState *localseq;
+
+	amstate = sequence_read_state(seqh);
+	localseq = (LocalSequenceState *) DatumGetPointer(amstate);
+
+	localseq->last_value = new_value;		/* last fetched number */
+	localseq->is_called = true;
+	localseq->log_cnt = 0;			/* how much is logged */
+
+	sequence_start_update(seqh, true);
+	sequence_save_state(seqh, PointerGetDatum(localseq), true);
+	sequence_finish_update(seqh);
+
+	sequence_release_tuple(seqh);
+}
+
+/*
+ * seqam_local_get_state()
+ *
+ * Dump state of a local sequence (for pg_dump)
+ */
+static Datum
+seqam_local_get_state(Relation seqrel, SequenceHandle *seqh)
+{
+	Datum				amstate;
+	LocalSequenceState *localseq = palloc(sizeof(LocalSequenceState));
+
+	amstate = sequence_read_state(seqh);
+	memcpy(localseq, DatumGetPointer(amstate), sizeof(LocalSequenceState));
+	sequence_release_tuple(seqh);
+
+	return PointerGetDatum(localseq);
+}
+
+/*
+ * seqam_local_set_state()
+ *
+ * Restore previously dumped state of local sequence (used by pg_dump)
+*/
+static void
+seqam_local_set_state(Relation seqrel, SequenceHandle *seqh,
+					  Datum amstate)
+{
+	Form_pg_sequence	seq;
+	LocalSequenceState *localseq;
+
+	seq = sequence_read_options(seqh);
+	localseq = (LocalSequenceState *) DatumGetPointer(amstate);
+
+	sequence_check_range(localseq->last_value, seq->min_value, seq->max_value,
+						 "last_value");
+
+	sequence_start_update(seqh, true);
+	sequence_save_state(seqh, amstate, true);
+	sequence_finish_update(seqh);
+
+	sequence_release_tuple(seqh);
+}
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 41d2fd4..e684f60 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -251,6 +251,7 @@ Boot_CreateStmt:
 													  false,
 													  true,
 													  false,
+													  InvalidOid,
 													  NULL);
 						elog(DEBUG4, "relation created with OID %u", id);
 					}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e997b57..b7cd40a 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -41,6 +41,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/objectaccess.h"
+#include "catalog/pg_am.h"
 #include "catalog/pg_attrdef.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
@@ -88,6 +89,7 @@ static void AddNewRelationTuple(Relation pg_class_desc,
 					Oid reloftype,
 					Oid relowner,
 					char relkind,
+					Oid relam,
 					Datum relacl,
 					Datum reloptions);
 static ObjectAddress AddNewRelationType(const char *typeName,
@@ -849,6 +851,7 @@ AddNewRelationTuple(Relation pg_class_desc,
 					Oid reloftype,
 					Oid relowner,
 					char relkind,
+					Oid relam,
 					Datum relacl,
 					Datum reloptions)
 {
@@ -922,6 +925,7 @@ AddNewRelationTuple(Relation pg_class_desc,
 	new_rel_reltup->relowner = relowner;
 	new_rel_reltup->reltype = new_type_oid;
 	new_rel_reltup->reloftype = reloftype;
+	new_rel_reltup->relam = relam;
 
 	new_rel_desc->rd_att->tdtypeid = new_type_oid;
 
@@ -1035,6 +1039,7 @@ heap_create_with_catalog(const char *relname,
 						 bool use_user_acl,
 						 bool allow_system_table_mods,
 						 bool is_internal,
+						 Oid relam,
 						 ObjectAddress *typaddress)
 {
 	Relation	pg_class_desc;
@@ -1263,6 +1268,7 @@ heap_create_with_catalog(const char *relname,
 						reloftypeid,
 						ownerid,
 						relkind,
+						relam,
 						PointerGetDatum(relacl),
 						reloptions);
 
@@ -1275,7 +1281,8 @@ heap_create_with_catalog(const char *relname,
 	/*
 	 * Make a dependency link to force the relation to be deleted if its
 	 * namespace is.  Also make a dependency link to its owner, as well as
-	 * dependencies for any roles mentioned in the default ACL.
+	 * dependencies for any roles mentioned in the default ACL. When relam
+	 * is specified, record dependency on the pg_am record.
 	 *
 	 * For composite types, these dependencies are tracked for the pg_type
 	 * entry, so we needn't record them here.  Likewise, TOAST tables don't
@@ -1330,6 +1337,14 @@ heap_create_with_catalog(const char *relname,
 								  0, NULL,
 								  nnewmembers, newmembers);
 		}
+
+		if (relkind == RELKIND_SEQUENCE)
+		{
+			referenced.classId = AccessMethodRelationId;
+			referenced.objectId = relam;
+			referenced.objectSubId = 0;
+			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+		}
 	}
 
 	/* Post creation hook for new relation */
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index cb3ba85..b40f0c7 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -16,6 +16,7 @@
 #include "postgres.h"
 
 #include "access/htup_details.h"
+#include "access/seqamapi.h"
 #include "access/sysattr.h"
 #include "catalog/catalog.h"
 #include "catalog/indexing.h"
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index f40a005..40b5e91 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -291,6 +291,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 										   false,
 										   true,
 										   true,
+										   InvalidOid,
 										   NULL);
 	Assert(toast_relid != InvalidOid);
 
diff --git a/src/backend/commands/amcmds.c b/src/backend/commands/amcmds.c
index 68ea5f3..1f2e0c4 100644
--- a/src/backend/commands/amcmds.c
+++ b/src/backend/commands/amcmds.c
@@ -15,6 +15,8 @@
 
 #include "access/heapam.h"
 #include "access/htup_details.h"
+#include "access/seqamapi.h"
+#include "access/xact.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_am.h"
@@ -29,7 +31,7 @@
 #include "utils/syscache.h"
 
 
-static Oid	lookup_index_am_handler_func(List *handler_name, char amtype);
+static Oid	lookup_am_handler_func(List *handler_name, char amtype);
 static const char *get_am_type_string(char amtype);
 
 
@@ -72,7 +74,7 @@ CreateAccessMethod(CreateAmStmt *stmt)
 	/*
 	 * Get the handler function oid, verifying the AM type while at it.
 	 */
-	amhandler = lookup_index_am_handler_func(stmt->handler_name, stmt->amtype);
+	amhandler = lookup_am_handler_func(stmt->handler_name, stmt->amtype);
 
 	/*
 	 * Insert tuple into pg_am.
@@ -187,6 +189,16 @@ get_index_am_oid(const char *amname, bool missing_ok)
 }
 
 /*
+ * get_seq_am_oid - given an access method name, look up its OID
+ *		and verify it corresponds to an sequence AM.
+ */
+Oid
+get_seq_am_oid(const char *amname, bool missing_ok)
+{
+	return get_am_type_oid(amname, AMTYPE_SEQUENCE, missing_ok);
+}
+
+/*
  * get_am_oid - given an access method name, look up its OID.
  * 		The type is not checked.
  */
@@ -226,6 +238,8 @@ get_am_type_string(char amtype)
 	{
 		case AMTYPE_INDEX:
 			return "INDEX";
+		case AMTYPE_SEQUENCE:
+			return "SEQUENCE";
 		default:
 			/* shouldn't happen */
 			elog(ERROR, "invalid access method type '%c'", amtype);
@@ -240,9 +254,10 @@ get_am_type_string(char amtype)
  * This function either return valid function Oid or throw an error.
  */
 static Oid
-lookup_index_am_handler_func(List *handler_name, char amtype)
+lookup_am_handler_func(List *handler_name, char amtype)
 {
 	Oid			handlerOid;
+	Oid			handler_type;
 	static const Oid funcargtypes[1] = {INTERNALOID};
 
 	if (handler_name == NIL)
@@ -257,16 +272,21 @@ lookup_index_am_handler_func(List *handler_name, char amtype)
 	switch (amtype)
 	{
 		case AMTYPE_INDEX:
-			if (get_func_rettype(handlerOid) != INDEX_AM_HANDLEROID)
-				ereport(ERROR,
-						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-						 errmsg("function %s must return type \"%s\"",
-								NameListToString(handler_name),
-								"index_am_handler")));
+			handler_type = INDEX_AM_HANDLEROID;
+			break;
+		case AMTYPE_SEQUENCE:
+			handler_type = SEQ_AM_HANDLEROID;
 			break;
 		default:
 			elog(ERROR, "unrecognized access method type \"%c\"", amtype);
 	}
 
+	if (get_func_rettype(handlerOid) != handler_type)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("function %s must return type \"%s\"",
+						NameListToString(handler_name),
+						format_type_be(handler_type))));
+
 	return handlerOid;
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 5cb28cf..54a22da 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -680,6 +680,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, char relpersistence,
 										  false,
 										  true,
 										  true,
+										  InvalidOid,
 										  NULL);
 	Assert(OIDNewHeap != InvalidOid);
 
diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c
index cb7a145..ab7b7a3 100644
--- a/src/backend/commands/createas.c
+++ b/src/backend/commands/createas.c
@@ -385,7 +385,8 @@ intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
 	/*
 	 * Actually create the target table
 	 */
-	intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL);
+	intoRelationAddr = DefineRelation(create, relkind, InvalidOid, InvalidOid,
+									  NULL);
 
 	/*
 	 * If necessary, create a TOAST table for the target table.  Note that
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 13b04e6..92ae4db 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -536,7 +536,7 @@ DefineIndex(Oid relationId,
 	reloptions = transformRelOptions((Datum) 0, stmt->options,
 									 NULL, NULL, false, false);
 
-	(void) index_reloptions(amoptions, reloptions, true);
+	(void) am_reloptions(amoptions, reloptions, true);
 
 	/*
 	 * Prepare arguments for index_create, primarily an IndexInfo structure.
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index c98f981..f7edcee 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -14,16 +14,22 @@
  */
 #include "postgres.h"
 
+#include "access/reloptions.h"
+#include "access/seqamapi.h"
+#include "access/transam.h"
 #include "access/htup_details.h"
 #include "access/multixact.h"
 #include "access/transam.h"
+#include "access/tupmacs.h"
 #include "access/xact.h"
 #include "access/xlog.h"
 #include "access/xloginsert.h"
 #include "access/xlogutils.h"
 #include "catalog/dependency.h"
+#include "catalog/indexing.h"
 #include "catalog/namespace.h"
 #include "catalog/objectaccess.h"
+#include "catalog/pg_am.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
 #include "commands/sequence.h"
@@ -36,19 +42,14 @@
 #include "storage/smgr.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
+#include "utils/int8.h"
 #include "utils/lsyscache.h"
+#include "utils/rel.h"
 #include "utils/resowner.h"
 #include "utils/syscache.h"
 
 
 /*
- * We don't want to log each fetching of a value from a sequence,
- * so we pre-log a few fetches in advance. In the event of
- * crash we can lose (skip over) as many values as we pre-logged.
- */
-#define SEQ_LOG_VALS	32
-
-/*
  * The "special area" of a sequence's buffer page looks like this.
  */
 #define SEQ_MAGIC	  0x1717
@@ -81,24 +82,113 @@ typedef SeqTableData *SeqTable;
 
 static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */
 
+struct SequenceHandle
+{
+	SeqTable	elm;
+	Relation	rel;
+	Buffer		buf;
+	Oid			statetyp;
+	int16		statetyplen;
+	bool		statetypbyval;
+	char		statetypalign;
+	bool		inupdate;
+	HeapTupleData tup;
+};
+
 /*
  * last_used_seq is updated by nextval() to point to the last used
  * sequence.
  */
 static SeqTableData *last_used_seq = NULL;
 
+static HeapTuple build_seq_tuple(Relation rel, SeqAmRoutine *seqam,
+								 Form_pg_sequence new, int64 restart_value);
 static void fill_seq_with_data(Relation rel, HeapTuple tuple);
 static int64 nextval_internal(Oid relid);
 static Relation open_share_lock(SeqTable seq);
 static void create_seq_hashtable(void);
-static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
-static Form_pg_sequence read_seq_tuple(SeqTable elm, Relation rel,
-			   Buffer *buf, HeapTuple seqtuple);
 static void init_params(List *options, bool isInit,
 			Form_pg_sequence new, List **owned_by);
-static void do_setval(Oid relid, int64 next, bool iscalled);
 static void process_owned_by(Relation seqrel, List *owned_by);
+static void log_sequence_tuple(Relation seqrel, HeapTuple tuple,
+							   Buffer buf, Page page);
+static HeapTuple sequence_read_tuple(SequenceHandle *seqh);
 
+/*
+ * Build template column definition for a sequence relation.
+*/
+static ColumnDef *
+makeSeqColumnDef(void)
+{
+	ColumnDef  *coldef = makeNode(ColumnDef);
+
+	coldef->inhcount = 0;
+	coldef->is_local = true;
+	coldef->is_not_null = true;
+	coldef->is_from_type = false;
+	/* Force plain storage. */
+	coldef->storage = 'p';
+	coldef->raw_default = NULL;
+	coldef->cooked_default = NULL;
+	coldef->collClause = NULL;
+	coldef->collOid = InvalidOid;
+	coldef->constraints = NIL;
+	coldef->location = -1;
+
+	return coldef;
+}
+
+/*
+ * Add additional sequence AM columns to the sequence column definition list.
+ */
+static List *
+BuildSeqColumnDefList(Oid amstateTypeOid)
+{
+	List	   *seqcols;
+	int			colid;
+
+	seqcols = NIL;
+	for (colid = SEQ_COL_FIRSTCOL; colid <= SEQ_COL_LASTCOL; colid++)
+	{
+		ColumnDef  *coldef = makeSeqColumnDef();
+
+		switch (colid)
+		{
+			case SEQ_COL_STARTVAL:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "start_value";
+				break;
+			case SEQ_COL_INCBY:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "increment_by";
+				break;
+			case SEQ_COL_MAXVALUE:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "max_value";
+				break;
+			case SEQ_COL_MINVALUE:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "min_value";
+				break;
+			case SEQ_COL_CACHE:
+				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
+				coldef->colname = "cache_value";
+				break;
+			case SEQ_COL_CYCLE:
+				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
+				coldef->colname = "is_cycled";
+				break;
+			case SEQ_COL_AMSTATE:
+				coldef->typeName = makeTypeNameFromOid(amstateTypeOid, -1);
+				coldef->colname = "amstate";
+				break;
+		}
+
+		seqcols = lappend(seqcols, coldef);
+	}
+
+	return seqcols;
+}
 
 /*
  * DefineSequence
@@ -111,14 +201,12 @@ DefineSequence(CreateSeqStmt *seq)
 	List	   *owned_by;
 	CreateStmt *stmt = makeNode(CreateStmt);
 	Oid			seqoid;
+	Oid			seqamid;
 	ObjectAddress address;
 	Relation	rel;
 	HeapTuple	tuple;
-	TupleDesc	tupDesc;
-	Datum		value[SEQ_COL_LASTCOL];
-	bool		null[SEQ_COL_LASTCOL];
-	int			i;
-	NameData	name;
+	List	   *seqcols;
+	SeqAmRoutine *seqam;
 
 	/* Unlogged sequences are not implemented -- not clear if useful. */
 	if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED)
@@ -147,102 +235,33 @@ DefineSequence(CreateSeqStmt *seq)
 	/* Check and set all option values */
 	init_params(seq->options, true, &new, &owned_by);
 
-	/*
-	 * Create relation (and fill value[] and null[] for the tuple)
-	 */
-	stmt->tableElts = NIL;
-	for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
-	{
-		ColumnDef  *coldef = makeNode(ColumnDef);
-
-		coldef->inhcount = 0;
-		coldef->is_local = true;
-		coldef->is_not_null = true;
-		coldef->is_from_type = false;
-		coldef->storage = 0;
-		coldef->raw_default = NULL;
-		coldef->cooked_default = NULL;
-		coldef->collClause = NULL;
-		coldef->collOid = InvalidOid;
-		coldef->constraints = NIL;
-		coldef->location = -1;
-
-		null[i - 1] = false;
-
-		switch (i)
-		{
-			case SEQ_COL_NAME:
-				coldef->typeName = makeTypeNameFromOid(NAMEOID, -1);
-				coldef->colname = "sequence_name";
-				namestrcpy(&name, seq->sequence->relname);
-				value[i - 1] = NameGetDatum(&name);
-				break;
-			case SEQ_COL_LASTVAL:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "last_value";
-				value[i - 1] = Int64GetDatumFast(new.last_value);
-				break;
-			case SEQ_COL_STARTVAL:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "start_value";
-				value[i - 1] = Int64GetDatumFast(new.start_value);
-				break;
-			case SEQ_COL_INCBY:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "increment_by";
-				value[i - 1] = Int64GetDatumFast(new.increment_by);
-				break;
-			case SEQ_COL_MAXVALUE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "max_value";
-				value[i - 1] = Int64GetDatumFast(new.max_value);
-				break;
-			case SEQ_COL_MINVALUE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "min_value";
-				value[i - 1] = Int64GetDatumFast(new.min_value);
-				break;
-			case SEQ_COL_CACHE:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "cache_value";
-				value[i - 1] = Int64GetDatumFast(new.cache_value);
-				break;
-			case SEQ_COL_LOG:
-				coldef->typeName = makeTypeNameFromOid(INT8OID, -1);
-				coldef->colname = "log_cnt";
-				value[i - 1] = Int64GetDatum((int64) 0);
-				break;
-			case SEQ_COL_CYCLE:
-				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
-				coldef->colname = "is_cycled";
-				value[i - 1] = BoolGetDatum(new.is_cycled);
-				break;
-			case SEQ_COL_CALLED:
-				coldef->typeName = makeTypeNameFromOid(BOOLOID, -1);
-				coldef->colname = "is_called";
-				value[i - 1] = BoolGetDatum(false);
-				break;
-		}
-		stmt->tableElts = lappend(stmt->tableElts, coldef);
-	}
+	if (seq->accessMethod)
+		seqamid = get_seq_am_oid(seq->accessMethod, false);
+	else
+		seqamid = LOCAL_SEQAM_OID;
+
+	seqam = GetSeqAmRoutineByAMId(seqamid);
+	/* Build column definitions. */
+	seqcols = BuildSeqColumnDefList(seqam->StateTypeOid);
 
 	stmt->relation = seq->sequence;
 	stmt->inhRelations = NIL;
 	stmt->constraints = NIL;
-	stmt->options = NIL;
+	stmt->options = seq->amoptions;
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
 	stmt->if_not_exists = seq->if_not_exists;
+	stmt->tableElts = seqcols;
 
-	address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL);
+	address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, seqamid,
+							 NULL);
 	seqoid = address.objectId;
 	Assert(seqoid != InvalidOid);
 
 	rel = heap_open(seqoid, AccessExclusiveLock);
-	tupDesc = RelationGetDescr(rel);
 
-	/* now initialize the sequence's data */
-	tuple = heap_form_tuple(tupDesc, value, null);
+	/* Build new sequence tuple and store it. */
+	tuple = build_seq_tuple(rel, seqam, &new, new.start_value);
 	fill_seq_with_data(rel, tuple);
 
 	/* process OWNED BY if given */
@@ -254,6 +273,7 @@ DefineSequence(CreateSeqStmt *seq)
 	return address;
 }
 
+
 /*
  * Reset a sequence to its initial value.
  *
@@ -267,58 +287,89 @@ DefineSequence(CreateSeqStmt *seq)
  * responsible for permissions checking.
  */
 void
-ResetSequence(Oid seq_relid)
+ResetSequence(Oid seqrelid)
 {
-	Relation	seq_rel;
-	SeqTable	elm;
-	Form_pg_sequence seq;
-	Buffer		buf;
-	HeapTupleData seqtuple;
 	HeapTuple	tuple;
+	Relation	seqrel;
+	SequenceHandle		seqh;
+	Form_pg_sequence	seq;
+	TupleDesc			tupDesc;
+	Datum	   values[SEQ_COL_LASTCOL];
+	bool	   nulls[SEQ_COL_LASTCOL];
+	SeqAmRoutine *seqam;
 
 	/*
-	 * Read the old sequence.  This does a bit more work than really
-	 * necessary, but it's simple, and we do want to double-check that it's
-	 * indeed a sequence.
+	 * Read and lock the old page.
 	 */
-	init_sequence(seq_relid, &elm, &seq_rel);
-	(void) read_seq_tuple(elm, seq_rel, &buf, &seqtuple);
+	sequence_open(seqrelid, &seqh);
+	tuple = sequence_read_tuple(&seqh);
+	seqrel = seqh.rel;
+	seqam = GetSeqAmRoutineForRelation(seqrel);
 
 	/*
 	 * Copy the existing sequence tuple.
 	 */
-	tuple = heap_copytuple(&seqtuple);
+	tuple = heap_copytuple(tuple);
 
 	/* Now we're done with the old page */
-	UnlockReleaseBuffer(buf);
+	sequence_release_tuple(&seqh);
 
-	/*
-	 * Modify the copied tuple to execute the restart (compare the RESTART
-	 * action in AlterSequence)
-	 */
 	seq = (Form_pg_sequence) GETSTRUCT(tuple);
-	seq->last_value = seq->start_value;
-	seq->is_called = false;
-	seq->log_cnt = 0;
+	tupDesc = RelationGetDescr(seqrel);
+	heap_deform_tuple(tuple, tupDesc, values, nulls);
+	values[SEQ_COL_AMSTATE - 1] = seqam->Init(seqrel, seq, seq->start_value,
+											  true, false);
+	tuple = heap_form_tuple(tupDesc, values, nulls);
 
 	/*
 	 * Create a new storage file for the sequence.  We want to keep the
 	 * sequence's relfrozenxid at 0, since it won't contain any unfrozen XIDs.
 	 * Same with relminmxid, since a sequence will never contain multixacts.
 	 */
-	RelationSetNewRelfilenode(seq_rel, seq_rel->rd_rel->relpersistence,
+	RelationSetNewRelfilenode(seqrel, seqh.rel->rd_rel->relpersistence,
 							  InvalidTransactionId, InvalidMultiXactId);
 
 	/*
 	 * Insert the modified tuple into the new storage file.
 	 */
-	fill_seq_with_data(seq_rel, tuple);
+	fill_seq_with_data(seqrel, tuple);
 
 	/* Clear local cache so that we don't think we have cached numbers */
 	/* Note that we do not change the currval() state */
-	elm->cached = elm->last;
+	seqh.elm->cached = seqh.elm->last;
 
-	relation_close(seq_rel, NoLock);
+	/* And we're done, close the sequence. */
+	sequence_close(&seqh);
+}
+
+/*
+ * Build sequence tuple based on the sequence form and fill in the
+ * sequence AM specific info as well.
+ */
+static HeapTuple
+build_seq_tuple(Relation rel, SeqAmRoutine *seqam, Form_pg_sequence new,
+				int64 restart_value)
+{
+	TupleDesc	tupDesc;
+	HeapTuple	tuple;
+	Datum		values[SEQ_COL_LASTCOL];
+	bool		nulls[SEQ_COL_LASTCOL];
+
+	tupDesc = RelationGetDescr(rel);
+
+	memset(nulls, 0, sizeof(nulls));
+
+	values[SEQ_COL_STARTVAL - 1] = Int64GetDatumFast(new->start_value);
+	values[SEQ_COL_INCBY - 1] = Int64GetDatumFast(new->increment_by);
+	values[SEQ_COL_MAXVALUE - 1] = Int64GetDatumFast(new->max_value);
+	values[SEQ_COL_MINVALUE - 1] = Int64GetDatumFast(new->min_value);
+	values[SEQ_COL_CACHE - 1] = Int64GetDatumFast(new->cache_value);
+	values[SEQ_COL_CYCLE - 1] = BoolGetDatum(new->is_cycled);
+	values[SEQ_COL_AMSTATE - 1] = seqam->Init(rel, new, restart_value,
+											  false, true);
+	tuple = heap_form_tuple(tupDesc, values, nulls);
+
+	return tuple;
 }
 
 /*
@@ -361,7 +412,13 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 	tuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
 	ItemPointerSet(&tuple->t_data->t_ctid, 0, FirstOffsetNumber);
 
-	/* check the comment above nextval_internal()'s equivalent call. */
+	/*
+	 * If something needs to be WAL logged, make sure that xid was acquired,
+	 * so this transaction's commit will trigger a WAL flush and wait for
+	 * syncrep. It's sufficient to ensure the toplevel transaction has a xid,
+	 * no need to assign xids subxacts, that'll already trigger a appropriate
+	 * wait. (Has to be done outside of critical section).
+	 */
 	if (RelationNeedsWAL(rel))
 		GetTopTransactionId();
 
@@ -375,23 +432,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 		elog(ERROR, "failed to add sequence tuple to page");
 
 	/* XLOG stuff */
-	if (RelationNeedsWAL(rel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
-
-		xlrec.node = rel->rd_node;
-
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
-		XLogRegisterData((char *) tuple->t_data, tuple->t_len);
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
-
-		PageSetLSN(page, recptr);
-	}
+	log_sequence_tuple(rel, tuple, buf, page);
 
 	END_CRIT_SECTION();
 
@@ -399,6 +440,69 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 }
 
 /*
+ * Replace the type of amstate column.
+ *
+ * We don't do AlterTable here as that produces dead columns which we don't
+ * want. This is safe because the sequence page is controlled by code in this
+ * module and isn't changed the same way as a table.
+ *
+ * TODO: check if anybody is depending on the row-type associated with the
+ * sequence.
+ */
+static void
+replace_sequence_amstate_col(Oid seqrelid, Oid typid)
+{
+	Relation	attr_rel;
+	Datum		values[Natts_pg_attribute];
+	bool		nulls[Natts_pg_attribute];
+	bool		replace[Natts_pg_attribute];
+	HeapTuple	tp,
+				attr_tuple,
+				newattr_tuple;
+	Form_pg_type	typtup;
+
+	tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+	if (!HeapTupleIsValid(tp))
+		elog(ERROR, "cache lookup failed for type %u", typid);
+
+	typtup = (Form_pg_type) GETSTRUCT(tp);
+
+	memset(nulls, 0, sizeof(nulls));
+	memset(replace, 0, sizeof(replace));
+
+	replace[Anum_pg_attribute_atttypid - 1] = true;
+	replace[Anum_pg_attribute_attlen - 1] = true;
+	replace[Anum_pg_attribute_attbyval - 1] = true;
+	replace[Anum_pg_attribute_attalign - 1] = true;
+
+	values[Anum_pg_attribute_atttypid - 1] = ObjectIdGetDatum(typid);
+	values[Anum_pg_attribute_attlen - 1] = Int16GetDatum(typtup->typlen);
+	values[Anum_pg_attribute_attbyval - 1] = BoolGetDatum(typtup->typbyval);
+	values[Anum_pg_attribute_attalign - 1] = CharGetDatum(typtup->typalign);
+
+	/* Build DROP command for amstate of old AM. */
+	attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
+
+	attr_tuple = SearchSysCache2(ATTNUM,
+								 ObjectIdGetDatum(seqrelid),
+								 Int16GetDatum(SEQ_COL_AMSTATE));
+	if (!HeapTupleIsValid(attr_tuple))		/* shouldn't happen */
+		elog(ERROR, "cache lookup failed for attribute %d of relation %u",
+			 SEQ_COL_AMSTATE, seqrelid);
+
+	newattr_tuple = heap_modify_tuple(attr_tuple, RelationGetDescr(attr_rel),
+									  values, nulls, replace);
+	simple_heap_update(attr_rel, &newattr_tuple->t_self, newattr_tuple);
+	CatalogUpdateIndexes(attr_rel, newattr_tuple);
+
+	ReleaseSysCache(tp);
+	heap_freetuple(newattr_tuple);
+	ReleaseSysCache(attr_tuple);
+
+	heap_close(attr_rel, RowExclusiveLock);
+}
+
+/*
  * AlterSequence
  *
  * Modify the definition of a sequence relation
@@ -406,19 +510,24 @@ fill_seq_with_data(Relation rel, HeapTuple tuple)
 ObjectAddress
 AlterSequence(AlterSeqStmt *stmt)
 {
-	Oid			relid;
-	SeqTable	elm;
+	Oid			seqrelid;
+	Oid			oldamid;
+	Oid			seqamid;
+	HeapTuple	tuple;
 	Relation	seqrel;
-	Buffer		buf;
-	HeapTupleData seqtuple;
-	Form_pg_sequence seq;
-	FormData_pg_sequence new;
+	Form_pg_sequence seq,
+					 new;
 	List	   *owned_by;
 	ObjectAddress address;
+	int64		restart_value;
+	bool		restart_requested;
+	SequenceHandle seqh;
+	SeqAmRoutine *oldseqam;
 
 	/* Open and lock sequence. */
-	relid = RangeVarGetRelid(stmt->sequence, AccessShareLock, stmt->missing_ok);
-	if (relid == InvalidOid)
+	seqrelid = RangeVarGetRelid(stmt->sequence, AccessExclusiveLock, stmt->missing_ok);
+
+	if (seqrelid == InvalidOid)
 	{
 		ereport(NOTICE,
 				(errmsg("relation \"%s\" does not exist, skipping",
@@ -426,70 +535,187 @@ AlterSequence(AlterSeqStmt *stmt)
 		return InvalidObjectAddress;
 	}
 
-	init_sequence(relid, &elm, &seqrel);
+	sequence_open(seqrelid, &seqh);
+	seqrel = seqh.rel;
+	oldamid = seqrel->rd_rel->relam;
+	oldseqam = GetSeqAmRoutineByAMId(oldamid);
 
 	/* allow ALTER to sequence owner only */
-	if (!pg_class_ownercheck(relid, GetUserId()))
+	if (!pg_class_ownercheck(seqrelid, GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
 					   stmt->sequence->relname);
 
 	/* lock page' buffer and read tuple into new sequence structure */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
+	tuple = sequence_read_tuple(&seqh);
+	seq = (Form_pg_sequence) GETSTRUCT(tuple);
 
 	/* Copy old values of options into workspace */
-	memcpy(&new, seq, sizeof(FormData_pg_sequence));
+	tuple = heap_copytuple(tuple);
+	new = (Form_pg_sequence) GETSTRUCT(tuple);
 
 	/* Check and set new values */
-	init_params(stmt->options, false, &new, &owned_by);
+	init_params(stmt->options, false, new, &owned_by);
 
-	/* Clear local cache so that we don't think we have cached numbers */
-	/* Note that we do not change the currval() state */
-	elm->cached = elm->last;
+	if (stmt->accessMethod)
+		seqamid = get_seq_am_oid(stmt->accessMethod, false);
+	else
+		seqamid = oldamid;
 
-	/* check the comment above nextval_internal()'s equivalent call. */
-	if (RelationNeedsWAL(seqrel))
-		GetTopTransactionId();
+	restart_value = sequence_get_restart_value(stmt->options, new->start_value,
+											   &restart_requested);
 
-	/* Now okay to update the on-disk tuple */
-	START_CRIT_SECTION();
+	/*
+	 * If we are changing sequence AM, we need to alter the sequence relation.
+	 */
+	if (seqamid != oldamid)
+	{
+		ObjectAddress	myself,
+						referenced;
+		Relation        pgcrel;
+		HeapTuple       pgctup,
+						newpgctuple;
+		HeapTuple       seqamtup;
+		Form_pg_am		form_am;
+		Datum			reloptions;
+		Datum			values[Natts_pg_class];
+		bool			nulls[Natts_pg_class];
+		bool			replace[Natts_pg_class];
+		static char	   *validnsps[2];
+		SeqAmRoutine	   *newseqam;
+
+		oldseqam = GetSeqAmRoutineByAMId(oldamid);
 
-	memcpy(seq, &new, sizeof(FormData_pg_sequence));
+		/*
+		 * If RESTART [WITH] option was not specified in ALTER SEQUENCE
+		 * statement, we use nextval of the old sequence AM to provide
+		 * restart point for the new sequence AM.
+		 */
+		if (!restart_requested)
+		{
+			int64 last;
+			restart_value = oldseqam->Alloc(seqrel, &seqh, 1, &last);
+		}
 
-	MarkBufferDirty(buf);
+		sequence_check_range(restart_value, new->min_value, new->max_value, "RESTART");
 
-	/* XLOG stuff */
-	if (RelationNeedsWAL(seqrel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-		Page		page = BufferGetPage(buf);
+		/* We don't need the old sequence tuple anymore. */
+		sequence_release_tuple(&seqh);
+
+		/* Parse the new reloptions. */
+		seqamtup = SearchSysCache1(AMOID, ObjectIdGetDatum(seqamid));
+		if (!HeapTupleIsValid(seqamtup))
+			elog(ERROR, "cache lookup failed for sequence access method %u",
+				 seqamid);
+
+		newseqam = GetSeqAmRoutineByAMId(seqamid);
+
+		form_am = (Form_pg_am) GETSTRUCT(seqamtup);
+
+		validnsps[0] = NameStr(form_am->amname);
+		validnsps[1] = NULL;
+
+		reloptions = transformRelOptions((Datum) 0, stmt->amoptions, NULL,
+										 validnsps, true, false);
 
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
+		(void) am_reloptions(newseqam->amoptions, reloptions, true);
+		ReleaseSysCache(seqamtup);
 
-		xlrec.node = seqrel->rd_node;
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
+		/* Update the pg_class entry. */
+		pgcrel = heap_open(RelationRelationId, RowExclusiveLock);
+		pgctup = SearchSysCache1(RELOID, ObjectIdGetDatum(seqrelid));
+		if (!HeapTupleIsValid(pgctup))
+			elog(ERROR, "pg_class entry for sequence %u unavailable",
+				 seqrelid);
 
-		XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
+		memset(values, 0, sizeof(values));
+		memset(nulls, false, sizeof(nulls));
+		memset(replace, false, sizeof(replace));
 
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
+		values[Anum_pg_class_relam - 1] = ObjectIdGetDatum(seqamid);
+		replace[Anum_pg_class_relam - 1] = true;
 
-		PageSetLSN(page, recptr);
+		if (reloptions != (Datum) 0)
+			values[Anum_pg_class_reloptions - 1] = reloptions;
+		else
+			nulls[Anum_pg_class_reloptions - 1] = true;
+		replace[Anum_pg_class_reloptions - 1] = true;
+
+		newpgctuple = heap_modify_tuple(pgctup, RelationGetDescr(pgcrel),
+										values, nulls, replace);
+
+		simple_heap_update(pgcrel, &newpgctuple->t_self, newpgctuple);
+
+		CatalogUpdateIndexes(pgcrel, newpgctuple);
+
+		heap_freetuple(newpgctuple);
+		ReleaseSysCache(pgctup);
+
+		heap_close(pgcrel, NoLock);
+
+		CommandCounterIncrement();
+
+		/*
+		 * Create a new storage file for the sequence.
+		 * And change the type definition.
+		 *
+		 * We can't use AlterTable internals here because the sequence
+		 * has to have the expected number of columns and no
+		 * attisdropped = true columns.
+		 */
+		RelationSetNewRelfilenode(seqrel, seqrel->rd_rel->relpersistence,
+								  InvalidTransactionId, InvalidMultiXactId);
+		replace_sequence_amstate_col(seqrelid, newseqam->StateTypeOid);
+		CommandCounterIncrement();
+
+		/* Rebuild the sequence tuple and save it. */
+		tuple = build_seq_tuple(seqrel, newseqam, new, restart_value);
+		fill_seq_with_data(seqh.rel, tuple);
+
+		/* Remove dependency on previous SeqAM */
+		deleteDependencyRecordsForClass(RelationRelationId, seqrelid,
+										AccessMethodRelationId,
+										DEPENDENCY_NORMAL);
+
+		/* Record dependency on new SeqAM */
+		myself.classId = RelationRelationId;
+		myself.objectId = seqrelid;
+		myself.objectSubId = 0;
+		referenced.classId = AccessMethodRelationId;
+		referenced.objectId = seqamid;
+		referenced.objectSubId = 0;
+		recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 	}
+	else
+	{
+		Datum	   newamstate;
 
-	END_CRIT_SECTION();
+		sequence_check_range(restart_value, new->min_value, new->max_value,
+							 restart_requested ? "RESTART" : "START");
 
-	UnlockReleaseBuffer(buf);
+		/* Let the new sequence AM initialize. */
+		newamstate = oldseqam->Init(seqrel, new, restart_value,
+									restart_requested, false);
+
+		sequence_start_update(&seqh, true);
+		memcpy(seq, new, sizeof(FormData_pg_sequence));
+		sequence_save_state(&seqh, newamstate, true);
+		sequence_finish_update(&seqh);
+		sequence_release_tuple(&seqh);
+	}
+
+	/* Clear local cache so that we don't think we have cached numbers */
+	/* Note that we do not change the currval() state */
+	seqh.elm->cached = seqh.elm->last;
 
 	/* process OWNED BY if given */
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
-	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+	InvokeObjectPostAlterHook(RelationRelationId, seqrelid, 0);
 
-	ObjectAddressSet(address, RelationRelationId, relid);
+	ObjectAddressSet(address, RelationRelationId, seqrelid);
 
-	relation_close(seqrel, NoLock);
+	sequence_close(&seqh);
 
 	return address;
 }
@@ -530,29 +756,26 @@ nextval_oid(PG_FUNCTION_ARGS)
 	PG_RETURN_INT64(nextval_internal(relid));
 }
 
+/*
+ * Sequence AM independent part of nextval() that does permission checking,
+ * returns cached values and then calls out to the SeqAM specific nextval part.
+ */
 static int64
 nextval_internal(Oid relid)
 {
 	SeqTable	elm;
 	Relation	seqrel;
-	Buffer		buf;
-	Page		page;
-	HeapTupleData seqtuple;
-	Form_pg_sequence seq;
-	int64		incby,
-				maxv,
-				minv,
-				cache,
-				log,
-				fetch,
-				last;
-	int64		result,
-				next,
-				rescnt = 0;
-	bool		logit = false;
+	Form_pg_sequence seq_form;
+	int64		last,
+				result;
+	SequenceHandle seqh;
+	SeqAmRoutine *seqam;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	sequence_open(relid, &seqh);
+	elm = seqh.elm;
+	seqrel = seqh.rel;
+	seqam = GetSeqAmRoutineForRelation(seqrel);
 
 	if (pg_class_aclcheck(elm->relid, GetUserId(),
 						  ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
@@ -577,121 +800,15 @@ nextval_internal(Oid relid)
 		Assert(elm->last_valid);
 		Assert(elm->increment != 0);
 		elm->last += elm->increment;
-		relation_close(seqrel, NoLock);
+		sequence_close(&seqh);
 		last_used_seq = elm;
 		return elm->last;
 	}
 
 	/* lock page' buffer and read tuple */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
-	page = BufferGetPage(buf);
-
-	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--;
-	}
+	seq_form = (Form_pg_sequence) GETSTRUCT(sequence_read_tuple(&seqh));
 
-	/*
-	 * Decide whether we should emit a WAL log record.  If so, force up the
-	 * fetch count to grab SEQ_LOG_VALS more values than we actually need to
-	 * cache.  (These will then be usable without logging.)
-	 *
-	 * If this is the first nextval after a checkpoint, we must force a new
-	 * WAL record to be written anyway, else replay starting from the
-	 * checkpoint would fail to advance the sequence past the logged values.
-	 * In this case we may as well fetch extra values.
-	 */
-	if (log < fetch || !seq->is_called)
-	{
-		/* forced log to satisfy local demand for values */
-		fetch = log = fetch + SEQ_LOG_VALS;
-		logit = true;
-	}
-	else
-	{
-		XLogRecPtr	redoptr = GetRedoRecPtr();
-
-		if (PageGetLSN(page) <= redoptr)
-		{
-			/* last update of seq was before checkpoint */
-			fetch = log = fetch + SEQ_LOG_VALS;
-			logit = true;
-		}
-	}
-
-	while (fetch)				/* try to fetch cache [+ log ] numbers */
-	{
-		/*
-		 * Check MAXVALUE for ascending sequences and MINVALUE for descending
-		 * sequences
-		 */
-		if (incby > 0)
-		{
-			/* ascending sequence */
-			if ((maxv >= 0 && next > maxv - incby) ||
-				(maxv < 0 && next + incby > maxv))
-			{
-				if (rescnt > 0)
-					break;		/* stop fetching */
-				if (!seq->is_cycled)
-				{
-					char		buf[100];
-
-					snprintf(buf, sizeof(buf), INT64_FORMAT, maxv);
-					ereport(ERROR,
-						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						   errmsg("nextval: reached maximum value of sequence \"%s\" (%s)",
-								  RelationGetRelationName(seqrel), buf)));
-				}
-				next = minv;
-			}
-			else
-				next += incby;
-		}
-		else
-		{
-			/* descending sequence */
-			if ((minv < 0 && next < minv - incby) ||
-				(minv >= 0 && next + incby < minv))
-			{
-				if (rescnt > 0)
-					break;		/* stop fetching */
-				if (!seq->is_cycled)
-				{
-					char		buf[100];
-
-					snprintf(buf, sizeof(buf), INT64_FORMAT, minv);
-					ereport(ERROR,
-						  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-						   errmsg("nextval: reached minimum value of sequence \"%s\" (%s)",
-								  RelationGetRelationName(seqrel), buf)));
-				}
-				next = maxv;
-			}
-			else
-				next += incby;
-		}
-		fetch--;
-		if (rescnt < cache)
-		{
-			log--;
-			rescnt++;
-			last = next;
-			if (rescnt == 1)	/* if it's first result - */
-				result = next;	/* it's what to return */
-		}
-	}
-
-	log -= fetch;				/* adjust for any unfetched numbers */
-	Assert(log >= 0);
+	result = seqam->Alloc(seqrel, &seqh, seq_form->cache_value, &last);
 
 	/* save info in local cache */
 	elm->last = result;			/* last returned number */
@@ -700,70 +817,8 @@ nextval_internal(Oid relid)
 
 	last_used_seq = elm;
 
-	/*
-	 * If something needs to be WAL logged, acquire an xid, so this
-	 * transaction's commit will trigger a WAL flush and wait for syncrep.
-	 * It's sufficient to ensure the toplevel transaction has an xid, no need
-	 * to assign xids subxacts, that'll already trigger an appropriate wait.
-	 * (Have to do that here, so we're outside the critical section)
-	 */
-	if (logit && RelationNeedsWAL(seqrel))
-		GetTopTransactionId();
-
-	/* ready to change the on-disk (or really, in-buffer) tuple */
-	START_CRIT_SECTION();
-
-	/*
-	 * We must mark the buffer dirty before doing XLogInsert(); see notes in
-	 * SyncOneBuffer().  However, we don't apply the desired changes just yet.
-	 * This looks like a violation of the buffer update protocol, but it is in
-	 * fact safe because we hold exclusive lock on the buffer.  Any other
-	 * process, including a checkpoint, that tries to examine the buffer
-	 * contents will block until we release the lock, and then will see the
-	 * final state that we install below.
-	 */
-	MarkBufferDirty(buf);
-
-	/* XLOG stuff */
-	if (logit && RelationNeedsWAL(seqrel))
-	{
-		xl_seq_rec	xlrec;
-		XLogRecPtr	recptr;
-
-		/*
-		 * We don't log the current state of the tuple, but rather the state
-		 * as it would appear after "log" more fetches.  This lets us skip
-		 * that many future WAL records, at the cost that we lose those
-		 * sequence values if we crash.
-		 */
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
-
-		/* set values that will be saved in xlog */
-		seq->last_value = next;
-		seq->is_called = true;
-		seq->log_cnt = 0;
-
-		xlrec.node = seqrel->rd_node;
-
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
-		XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
-
-		PageSetLSN(page, recptr);
-	}
-
-	/* Now update sequence tuple to the intended final state */
-	seq->last_value = last;		/* last fetched number */
-	seq->is_called = true;
-	seq->log_cnt = log;			/* how much is logged */
-
-	END_CRIT_SECTION();
-
-	UnlockReleaseBuffer(buf);
-
-	relation_close(seqrel, NoLock);
+	sequence_release_tuple(&seqh);
+	sequence_close(&seqh);
 
 	return result;
 }
@@ -773,28 +828,27 @@ currval_oid(PG_FUNCTION_ARGS)
 {
 	Oid			relid = PG_GETARG_OID(0);
 	int64		result;
-	SeqTable	elm;
-	Relation	seqrel;
+	SequenceHandle seqh;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	sequence_open(relid, &seqh);
 
-	if (pg_class_aclcheck(elm->relid, GetUserId(),
+	if (pg_class_aclcheck(seqh.elm->relid, GetUserId(),
 						  ACL_SELECT | ACL_USAGE) != ACLCHECK_OK)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied for sequence %s",
-						RelationGetRelationName(seqrel))));
+						RelationGetRelationName(seqh.rel))));
 
-	if (!elm->last_valid)
+	if (!seqh.elm->last_valid)
 		ereport(ERROR,
 				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 				 errmsg("currval of sequence \"%s\" is not yet defined in this session",
-						RelationGetRelationName(seqrel))));
+						RelationGetRelationName(seqh.rel))));
 
-	result = elm->last;
+	result = seqh.elm->last;
 
-	relation_close(seqrel, NoLock);
+	sequence_close(&seqh);
 
 	PG_RETURN_INT64(result);
 }
@@ -835,31 +889,26 @@ lastval(PG_FUNCTION_ARGS)
 }
 
 /*
- * Main internal procedure that handles 2 & 3 arg forms of SETVAL.
- *
- * Note that the 3 arg version (which sets the is_called flag) is
- * only for use in pg_dump, and setting the is_called flag may not
- * work if multiple users are attached to the database and referencing
- * the sequence (unlikely if pg_dump is restoring it).
- *
- * It is necessary to have the 3 arg version so that pg_dump can
- * restore the state of a sequence exactly during data-only restores -
- * it is the only way to clear the is_called flag in an existing
- * sequence.
+ * Implement the setval procedure.
  */
-static void
-do_setval(Oid relid, int64 next, bool iscalled)
+Datum
+setval_oid(PG_FUNCTION_ARGS)
 {
+	Oid			relid = PG_GETARG_OID(0);
+	int64		next = PG_GETARG_INT64(1);
 	SeqTable	elm;
 	Relation	seqrel;
-	Buffer		buf;
-	HeapTupleData seqtuple;
-	Form_pg_sequence seq;
+	SequenceHandle seqh;
+	SeqAmRoutine *seqam;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	sequence_open(relid, &seqh);
+	elm = seqh.elm;
+	seqrel = seqh.rel;
+	seqam = GetSeqAmRoutineForRelation(seqrel);
 
-	if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK)
+	if (pg_class_aclcheck(elm->relid, GetUserId(),
+						  ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied for sequence %s",
@@ -876,106 +925,86 @@ do_setval(Oid relid, int64 next, bool iscalled)
 	 */
 	PreventCommandIfParallelMode("setval()");
 
-	/* lock page' buffer and read tuple */
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
-
-	if ((next < seq->min_value) || (next > seq->max_value))
-	{
-		char		bufv[100],
-					bufm[100],
-					bufx[100];
-
-		snprintf(bufv, sizeof(bufv), INT64_FORMAT, next);
-		snprintf(bufm, sizeof(bufm), INT64_FORMAT, seq->min_value);
-		snprintf(bufx, sizeof(bufx), INT64_FORMAT, seq->max_value);
-		ereport(ERROR,
-				(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
-				 errmsg("setval: value %s is out of bounds for sequence \"%s\" (%s..%s)",
-						bufv, RelationGetRelationName(seqrel),
-						bufm, bufx)));
-	}
+	seqam->Setval(seqrel, &seqh, next);
 
-	/* 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 */
+	/* Reset local cached data */
+	elm->last = next;		/* last returned number */
+	elm->last_valid = true;
 	elm->cached = elm->last;
 
-	/* check the comment above nextval_internal()'s equivalent call. */
-	if (RelationNeedsWAL(seqrel))
-		GetTopTransactionId();
-
-	/* 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;
-		Page		page = BufferGetPage(buf);
-
-		XLogBeginInsert();
-		XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
-
-		xlrec.node = seqrel->rd_node;
-		XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
-		XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len);
-
-		recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
-
-		PageSetLSN(page, recptr);
-	}
-
-	END_CRIT_SECTION();
+	last_used_seq = elm;
 
-	UnlockReleaseBuffer(buf);
+	sequence_close(&seqh);
 
-	relation_close(seqrel, NoLock);
+	PG_RETURN_INT64(next);
 }
 
 /*
- * Implement the 2 arg setval procedure.
- * See do_setval for discussion.
+ * Implement the 3 arg setval procedure.
+ *
+ * This is a cludge for supporting old dumps.
+ *
+ * Check that the target sequence is local one and then convert this call
+ * to the seqam_restore call with apropriate data.
  */
 Datum
-setval_oid(PG_FUNCTION_ARGS)
+setval3_oid(PG_FUNCTION_ARGS)
 {
 	Oid			relid = PG_GETARG_OID(0);
 	int64		next = PG_GETARG_INT64(1);
+	bool		iscalled = PG_GETARG_BOOL(2);
+	LocalSequenceState	state;
+	SeqTable	elm;
+	Relation	seqrel;
+	SequenceHandle seqh;
+	SeqAmRoutine *seqam;
 
-	do_setval(relid, next, true);
+	/* open and AccessShareLock sequence */
+	sequence_open(relid, &seqh);
+	elm = seqh.elm;
+	seqrel = seqh.rel;
+	seqam = GetSeqAmRoutineForRelation(seqrel);
 
-	PG_RETURN_INT64(next);
-}
+	if (pg_class_aclcheck(elm->relid, GetUserId(),
+						  ACL_USAGE | ACL_UPDATE) != ACLCHECK_OK)
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied for sequence %s",
+							RelationGetRelationName(seqrel))));
+
+	/* read-only transactions may only modify temp sequences */
+	if (!seqrel->rd_islocaltemp)
+		PreventCommandIfReadOnly("setval()");
+
+	/* Make sure the target sequence is 'local' sequence. */
+	if (seqrel->rd_rel->relam != LOCAL_SEQAM_OID)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("the setval(oid, bigint, bool) function can only be called for \"local\" sequences")));
+
+	/* Build the state and pass it to sequence AM. */
+	state.last_value = next;
+	state.log_cnt = 0;
+	state.is_called = iscalled;
+	seqam->SetState(seqh.rel, &seqh, PointerGetDatum(&state));
+
+	/* Set the currval() state only if iscalled = true */
+	if (iscalled)
+	{
+		elm->last = next;		/* last returned number */
+		elm->last_valid = true;
+	}
 
-/*
- * Implement the 3 arg setval procedure.
- * See do_setval for discussion.
- */
-Datum
-setval3_oid(PG_FUNCTION_ARGS)
-{
-	Oid			relid = PG_GETARG_OID(0);
-	int64		next = PG_GETARG_INT64(1);
-	bool		iscalled = PG_GETARG_BOOL(2);
+	/* Reset local cached data */
+	elm->cached = elm->last;
+
+	last_used_seq = elm;
 
-	do_setval(relid, next, iscalled);
+	sequence_close(&seqh);
 
 	PG_RETURN_INT64(next);
 }
 
-
 /*
  * Open the sequence and acquire AccessShareLock if needed
  *
@@ -1034,11 +1063,10 @@ create_seq_hashtable(void)
 }
 
 /*
- * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
- * output parameters.
+ * Given a relation OID, open and share-lock the sequence.
  */
-static void
-init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
+void
+sequence_open(Oid relid, SequenceHandle *seqh)
 {
 	SeqTable	elm;
 	Relation	seqrel;
@@ -1090,44 +1118,59 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 	}
 
 	/* Return results */
-	*p_elm = elm;
-	*p_rel = seqrel;
+	seqh->elm = elm;
+	seqh->rel = seqrel;
+	seqh->buf = InvalidBuffer;
+	seqh->tup.t_data = NULL;
+	seqh->tup.t_len = 0;
+	seqh->statetyp = InvalidOid;
+	seqh->statetyplen = -1;
+	seqh->statetypbyval = false;
+	seqh->statetypalign = '\0';
+	seqh->inupdate = false;
 }
 
+/*
+ * Given the sequence handle, unlock the page buffer and close the relation
+ */
+void
+sequence_close(SequenceHandle *seqh)
+{
+	Assert(!seqh->inupdate);
+
+	relation_close(seqh->rel, NoLock);
+}
 
 /*
  * Given an opened sequence relation, lock the page buffer and find the tuple
- *
- * *buf receives the reference to the pinned-and-ex-locked buffer
- * *seqtuple receives the reference to the sequence tuple proper
- *		(this arg should point to a local variable of type HeapTupleData)
- *
- * Function's return value points to the data payload of the tuple
  */
-static Form_pg_sequence
-read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
+static HeapTuple
+sequence_read_tuple(SequenceHandle *seqh)
 {
 	Page		page;
+	Buffer		buf;
 	ItemId		lp;
 	sequence_magic *sm;
-	Form_pg_sequence seq;
 
-	*buf = ReadBuffer(rel, 0);
-	LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
+	if (seqh->tup.t_data != NULL)
+		return &seqh->tup;
+
+	seqh->buf = buf = ReadBuffer(seqh->rel, 0);
+	LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
 
-	page = BufferGetPage(*buf);
+	page = BufferGetPage(buf);
 	sm = (sequence_magic *) PageGetSpecialPointer(page);
 
 	if (sm->magic != SEQ_MAGIC)
 		elog(ERROR, "bad magic number in sequence \"%s\": %08X",
-			 RelationGetRelationName(rel), sm->magic);
+			 RelationGetRelationName(seqh->rel), sm->magic);
 
 	lp = PageGetItemId(page, FirstOffsetNumber);
 	Assert(ItemIdIsNormal(lp));
 
-	/* Note we currently only bother to set these two fields of *seqtuple */
-	seqtuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
-	seqtuple->t_len = ItemIdGetLength(lp);
+	/* Note we currently only bother to set these two fields of the tuple */
+	seqh->tup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
+	seqh->tup.t_len = ItemIdGetLength(lp);
 
 	/*
 	 * Previous releases of Postgres neglected to prevent SELECT FOR UPDATE on
@@ -1137,33 +1180,181 @@ read_seq_tuple(SeqTable elm, Relation rel, Buffer *buf, HeapTuple seqtuple)
 	 * bit update, ie, don't bother to WAL-log it, since we can certainly do
 	 * this again if the update gets lost.
 	 */
-	Assert(!(seqtuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI));
-	if (HeapTupleHeaderGetRawXmax(seqtuple->t_data) != InvalidTransactionId)
+	Assert(!(seqh->tup.t_data->t_infomask & HEAP_XMAX_IS_MULTI));
+	if (HeapTupleHeaderGetRawXmax(seqh->tup.t_data) != InvalidTransactionId)
+	{
+		HeapTupleHeaderSetXmax(seqh->tup.t_data, InvalidTransactionId);
+		seqh->tup.t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
+		seqh->tup.t_data->t_infomask |= HEAP_XMAX_INVALID;
+		MarkBufferDirtyHint(buf, true);
+	}
+
+	/* update our copy of the increment if needed */
+	if (seqh->elm->increment == 0)
+	{
+		Form_pg_sequence seq = (Form_pg_sequence) GETSTRUCT(&seqh->tup);
+		seqh->elm->increment = seq->increment_by;
+	}
+
+	return &seqh->tup;
+}
+
+Form_pg_sequence
+sequence_read_options(SequenceHandle *seqh)
+{
+	return (Form_pg_sequence) GETSTRUCT(sequence_read_tuple(seqh));
+}
+
+Datum
+sequence_read_state(SequenceHandle *seqh)
+{
+	HeapTuple		tuple = sequence_read_tuple(seqh);
+	bool			isnull;
+	TupleDesc		tupDesc;
+	Datum			res;
+
+	tupDesc = RelationGetDescr(seqh->rel);
+
+	res = fastgetattr(tuple, SEQ_COL_AMSTATE, tupDesc, &isnull);
+	Assert(!isnull);
+
+	return res;
+}
+
+/*
+ * Write a sequence tuple.
+ *
+ * If 'do_wal' is false, the update doesn't need to be WAL-logged. After
+ * a crash, you might get an old copy of the tuple.
+ *
+ * We split this into 3 step process so that the tuple may be safely updated
+ * inline.
+ */
+void
+sequence_start_update(SequenceHandle *seqh, bool dowal)
+{
+	Assert(seqh->tup.t_data != NULL && !seqh->inupdate);
+
+	if (seqh->statetyp == InvalidOid)
+	{
+		SeqAmRoutine *seqam = GetSeqAmRoutineForRelation(seqh->rel);
+		seqh->statetyp = seqam->StateTypeOid;
+
+		get_typlenbyvalalign(seqh->statetyp, &seqh->statetyplen,
+							 &seqh->statetypbyval, &seqh->statetypalign);
+		Assert(seqh->statetyplen > 0);
+	}
+
+	if (dowal)
+		GetTopTransactionId();
+
+	seqh->inupdate = true;
+
+	START_CRIT_SECTION();
+}
+
+void
+sequence_save_state(SequenceHandle *seqh, Datum amstate, bool dowal)
+{
+	char	   *seqstate = DatumGetPointer(sequence_read_state(seqh));
+	Page		page;
+
+	Assert(seqh->inupdate);
+
+
+	/*
+	 * Update the state data inline.
+	 *
+	 * This is only needed when the provided amstate datum points to different
+	 * data than what is already in the tuple.
+	 */
+	if (DatumGetPointer(amstate) != seqstate)
+	{
+		if (seqh->statetypbyval)
+			store_att_byval(seqstate, amstate, seqh->statetyplen);
+		else
+			memmove(seqstate, DatumGetPointer(amstate), seqh->statetyplen);
+	}
+
+	page = BufferGetPage(seqh->buf);
+	MarkBufferDirtyHint(seqh->buf, true);
+
+	if (dowal && RelationNeedsWAL(seqh->rel))
+		log_sequence_tuple(seqh->rel, &seqh->tup, seqh->buf, page);
+}
+
+void
+sequence_finish_update(SequenceHandle *seqh)
+{
+	Assert(seqh->inupdate);
+
+	END_CRIT_SECTION();
+
+	seqh->inupdate = false;
+}
+
+
+/*
+ * Release a tuple, read with sequence_read_tuple, without saving it
+ */
+void
+sequence_release_tuple(SequenceHandle *seqh)
+{
+	/* Remove the tuple from cache */
+	if (seqh->tup.t_data != NULL)
+	{
+		seqh->tup.t_data = NULL;
+		seqh->tup.t_len = 0;
+	}
+
+	/* Release the page lock */
+	if (BufferIsValid(seqh->buf))
 	{
-		HeapTupleHeaderSetXmax(seqtuple->t_data, InvalidTransactionId);
-		seqtuple->t_data->t_infomask &= ~HEAP_XMAX_COMMITTED;
-		seqtuple->t_data->t_infomask |= HEAP_XMAX_INVALID;
-		MarkBufferDirtyHint(*buf, true);
+		UnlockReleaseBuffer(seqh->buf);
+		seqh->buf = InvalidBuffer;
 	}
+}
+
+/*
+ * Returns true, if the next update to the sequence tuple needs to be
+ * WAL-logged because it's the first update after a checkpoint.
+ *
+ * The sequence AM can use this as a hint, if it wants to piggyback some extra
+ * actions on WAL-logged updates.
+ *
+ * NB: This is just a hint. even when sequence_needs_wal() returns 'false',
+ * the sequence access method might decide to WAL-log an update anyway.
+ */
+bool
+sequence_needs_wal(SequenceHandle *seqh)
+{
+	Page		page;
+	XLogRecPtr	redoptr;
 
-	seq = (Form_pg_sequence) GETSTRUCT(seqtuple);
+	Assert(BufferIsValid(seqh->buf));
 
-	/* this is a handy place to update our copy of the increment */
-	elm->increment = seq->increment_by;
+	if (!RelationNeedsWAL(seqh->rel))
+		return false;
 
-	return seq;
+	page = BufferGetPage(seqh->buf);
+	redoptr = GetRedoRecPtr();
+
+	return (PageGetLSN(page) <= redoptr);
 }
 
 /*
- * init_params: process the options list of CREATE or ALTER SEQUENCE,
+ * init_params: process the params list of CREATE or ALTER SEQUENCE,
  * and store the values into appropriate fields of *new.  Also set
- * *owned_by to any OWNED BY option, or to NIL if there is none.
+ * *owned_by to any OWNED BY param, or to NIL if there is none.
+ *
+ * If isInit is true, fill any unspecified params with default values;
+ * otherwise, do not change existing params that aren't explicitly overridden.
  *
- * If isInit is true, fill any unspecified options with default values;
- * otherwise, do not change existing options that aren't explicitly overridden.
+ * Note that only syntax check is done for RESTART [WITH] parameter, the actual
+ * handling of it should be done by init function of a sequence access method.
  */
 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;
@@ -1173,13 +1364,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)
 		{
@@ -1250,13 +1441,6 @@ init_params(List *options, bool isInit,
 				 defel->defname);
 	}
 
-	/*
-	 * We must reset log_cnt when isInit or when changing any parameters that
-	 * would affect future nextval allocations.
-	 */
-	if (isInit)
-		new->log_cnt = 0;
-
 	/* INCREMENT BY */
 	if (increment_by != NULL)
 	{
@@ -1265,7 +1449,6 @@ init_params(List *options, bool isInit,
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 					 errmsg("INCREMENT must not be zero")));
-		new->log_cnt = 0;
 	}
 	else if (isInit)
 		new->increment_by = 1;
@@ -1275,7 +1458,6 @@ init_params(List *options, bool isInit,
 	{
 		new->is_cycled = intVal(is_cycled->arg);
 		Assert(BoolIsValid(new->is_cycled));
-		new->log_cnt = 0;
 	}
 	else if (isInit)
 		new->is_cycled = false;
@@ -1284,7 +1466,6 @@ init_params(List *options, bool isInit,
 	if (max_value != NULL && max_value->arg)
 	{
 		new->max_value = defGetInt64(max_value);
-		new->log_cnt = 0;
 	}
 	else if (isInit || max_value != NULL)
 	{
@@ -1292,14 +1473,12 @@ init_params(List *options, bool isInit,
 			new->max_value = SEQ_MAXVALUE;		/* ascending seq */
 		else
 			new->max_value = -1;	/* descending seq */
-		new->log_cnt = 0;
 	}
 
 	/* MINVALUE (null arg means NO MINVALUE) */
 	if (min_value != NULL && min_value->arg)
 	{
 		new->min_value = defGetInt64(min_value);
-		new->log_cnt = 0;
 	}
 	else if (isInit || min_value != NULL)
 	{
@@ -1307,7 +1486,6 @@ init_params(List *options, bool isInit,
 			new->min_value = 1; /* ascending seq */
 		else
 			new->min_value = SEQ_MINVALUE;		/* descending seq */
-		new->log_cnt = 0;
 	}
 
 	/* crosscheck min/max */
@@ -1361,48 +1539,6 @@ init_params(List *options, bool isInit,
 					 bufs, bufm)));
 	}
 
-	/* RESTART [WITH] */
-	if (restart_value != NULL)
-	{
-		if (restart_value->arg != NULL)
-			new->last_value = defGetInt64(restart_value);
-		else
-			new->last_value = new->start_value;
-		new->is_called = false;
-		new->log_cnt = 0;
-	}
-	else if (isInit)
-	{
-		new->last_value = new->start_value;
-		new->is_called = false;
-	}
-
-	/* crosscheck RESTART (or current value, if changing MIN/MAX) */
-	if (new->last_value < new->min_value)
-	{
-		char		bufs[100],
-					bufm[100];
-
-		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
-		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			   errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
-					  bufs, bufm)));
-	}
-	if (new->last_value > new->max_value)
-	{
-		char		bufs[100],
-					bufm[100];
-
-		snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->last_value);
-		snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-			errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
-				   bufs, bufm)));
-	}
-
 	/* CACHE */
 	if (cache_value != NULL)
 	{
@@ -1417,7 +1553,6 @@ init_params(List *options, bool isInit,
 					 errmsg("CACHE (%s) must be greater than zero",
 							buf)));
 		}
-		new->log_cnt = 0;
 	}
 	else if (isInit)
 		new->cache_value = 1;
@@ -1528,20 +1663,17 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	TupleDesc	tupdesc;
 	Datum		values[5];
 	bool		isnull[5];
-	SeqTable	elm;
-	Relation	seqrel;
-	Buffer		buf;
-	HeapTupleData seqtuple;
 	Form_pg_sequence seq;
+	SequenceHandle  seqh;
 
 	/* open and AccessShareLock sequence */
-	init_sequence(relid, &elm, &seqrel);
+	sequence_open(relid, &seqh);
 
 	if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_UPDATE | ACL_USAGE) != ACLCHECK_OK)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("permission denied for sequence %s",
-						RelationGetRelationName(seqrel))));
+						RelationGetRelationName(seqh.rel))));
 
 	tupdesc = CreateTemplateTupleDesc(5, false);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "start_value",
@@ -1559,7 +1691,7 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 
 	memset(isnull, 0, sizeof(isnull));
 
-	seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple);
+	seq = (Form_pg_sequence) GETSTRUCT(sequence_read_tuple(&seqh));
 
 	values[0] = Int64GetDatum(seq->start_value);
 	values[1] = Int64GetDatum(seq->min_value);
@@ -1567,12 +1699,85 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
 	values[3] = Int64GetDatum(seq->increment_by);
 	values[4] = BoolGetDatum(seq->is_cycled);
 
-	UnlockReleaseBuffer(buf);
-	relation_close(seqrel, NoLock);
+	sequence_release_tuple(&seqh);
+	sequence_close(&seqh);
 
 	return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
 }
 
+Datum
+pg_sequence_get_state(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	Datum		state;
+	char	   *statestr;
+	SequenceHandle seqh;
+	SeqAmRoutine *seqam;
+	Oid			typoutput;
+	bool		typisvarlena;
+
+	/* Load the sequence AM */
+	sequence_open(relid, &seqh);
+	seqam = GetSeqAmRoutineForRelation(seqh.rel);
+
+	/* Get the type output function. */
+	getTypeOutputInfo(seqam->StateTypeOid, &typoutput, &typisvarlena);
+
+	/* Get the output and convert it to string. */
+	state = seqam->GetState(seqh.rel, &seqh);
+	statestr = OidOutputFunctionCall(typoutput, state);
+
+	sequence_close(&seqh);
+
+	PG_RETURN_TEXT_P(cstring_to_text(statestr));
+}
+
+Datum
+pg_sequence_set_state(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	char	   *statestr = text_to_cstring(PG_GETARG_TEXT_PP(1));
+	SequenceHandle seqh;
+	SeqAmRoutine *seqam;
+	Oid			typinput,
+				typioparam;
+	Datum		state;
+
+	/* Load the sequence AM */
+	sequence_open(relid, &seqh);
+	seqam = GetSeqAmRoutineForRelation(seqh.rel);
+
+	/* Get the type input function. */
+	getTypeInputInfo(seqam->StateTypeOid, &typinput, &typioparam);
+
+	/* Convert the string to the state type and set it as new state. */
+	state = OidInputFunctionCall(typinput, statestr, typioparam, -1);
+	seqam->SetState(seqh.rel, &seqh, state);
+
+	sequence_close(&seqh);
+
+	PG_RETURN_VOID();
+}
+
+static void
+log_sequence_tuple(Relation seqrel, HeapTuple tuple,
+				   Buffer buf, Page page)
+{
+	xl_seq_rec	xlrec;
+	XLogRecPtr	recptr;
+
+	XLogBeginInsert();
+	XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT);
+
+	xlrec.node = seqrel->rd_node;
+
+	XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec));
+	XLogRegisterData((char *) tuple->t_data, tuple->t_len);
+
+	recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG);
+
+	PageSetLSN(page, recptr);
+}
 
 void
 seq_redo(XLogReaderState *record)
@@ -1638,3 +1843,149 @@ ResetSequenceCaches(void)
 
 	last_used_seq = NULL;
 }
+
+/*
+ * Increment sequence while correctly handling overflows and min/max.
+ */
+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;
+}
+
+
+/*
+ * Check that new value, minimum and maximum are valid.
+ *
+ * Used by sequence AMs during sequence initialization to validate
+ * the sequence parameters.
+ */
+void
+sequence_check_range(int64 value, int64 min_value, int64 max_value, const char *valname)
+{
+	if (value < min_value)
+	{
+		char		bufs[100],
+					bufm[100];
+
+		snprintf(bufs, sizeof(bufs), INT64_FORMAT, value);
+		snprintf(bufm, sizeof(bufm), INT64_FORMAT, min_value);
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("%s value (%s) cannot be less than MINVALUE (%s)",
+						valname, bufs, bufm)));
+	}
+
+	if (value > max_value)
+	{
+		char		bufs[100],
+					bufm[100];
+
+		snprintf(bufs, sizeof(bufs), INT64_FORMAT, value);
+		snprintf(bufm, sizeof(bufm), INT64_FORMAT, max_value);
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+			  errmsg("%s value (%s) cannot be greater than MAXVALUE (%s)",
+					 valname, bufs, bufm)));
+	}
+
+}
+
+/*
+ * It's reasonable to expect many sequence AMs to care only about
+ * RESTART [WITH] option of ALTER SEQUENCE command, so we provide
+ * this interface for convenience.
+ * It is also useful for ALTER SEQUENCE USING.
+ */
+int64
+sequence_get_restart_value(List *options, int64 default_value, bool *found)
+{
+	ListCell *opt;
+
+	foreach(opt, options)
+	{
+		DefElem    *defel = (DefElem *) lfirst(opt);
+
+		if (strcmp(defel->defname, "restart") == 0)
+		{
+			*found = true;
+			if (defel->arg != NULL)
+				return defGetInt64(defel);
+			else
+				return default_value;
+		}
+	}
+
+	*found = false;
+	return default_value;
+}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 96dc923..6e6ee5d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -19,6 +19,7 @@
 #include "access/multixact.h"
 #include "access/reloptions.h"
 #include "access/relscan.h"
+#include "access/seqamapi.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "access/xlog.h"
@@ -269,6 +270,7 @@ struct DropRelationCallbackState
 #define		ATT_INDEX				0x0008
 #define		ATT_COMPOSITE_TYPE		0x0010
 #define		ATT_FOREIGN_TABLE		0x0020
+#define		ATT_SEQUENCE			0x0040
 
 static void truncate_check_rel(Relation rel);
 static List *MergeAttributes(List *schema, List *supers, char relpersistence,
@@ -454,7 +456,7 @@ static void RangeVarCallbackForAlterRelation(const RangeVar *rv, Oid relid,
  * ----------------------------------------------------------------
  */
 ObjectAddress
-DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
+DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, Oid relamid,
 			   ObjectAddress *typaddress)
 {
 	char		relname[NAMEDATALEN];
@@ -473,7 +475,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	Datum		reloptions;
 	ListCell   *listptr;
 	AttrNumber	attnum;
-	static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
 	Oid			ofTypeId;
 	ObjectAddress address;
 
@@ -551,13 +552,29 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 	/*
 	 * Parse and validate reloptions, if any.
 	 */
-	reloptions = transformRelOptions((Datum) 0, stmt->options, NULL, validnsps,
-									 true, false);
+	if (relkind == RELKIND_SEQUENCE)
+	{
+		SeqAmRoutine *seqam;
+
+		Assert(relamid != InvalidOid);
+		seqam = GetSeqAmRoutineByAMId(relamid);
+		reloptions = transformRelOptions((Datum) 0, stmt->options, NULL,
+										 NULL, true, false);
 
-	if (relkind == RELKIND_VIEW)
-		(void) view_reloptions(reloptions, true);
+		(void) am_reloptions(seqam->amoptions, reloptions, true);
+	}
 	else
-		(void) heap_reloptions(relkind, reloptions, true);
+	{
+		static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
+
+		Assert(relamid == InvalidOid);
+		reloptions = transformRelOptions((Datum) 0, stmt->options, NULL,
+										 validnsps, true, false);
+		if (relkind == RELKIND_VIEW)
+			(void) view_reloptions(reloptions, true);
+		else
+			(void) heap_reloptions(relkind, reloptions, true);
+	}
 
 	if (stmt->ofTypename)
 	{
@@ -678,6 +695,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
 										  true,
 										  allowSystemTableMods,
 										  false,
+										  relamid,
 										  typaddress);
 
 	/* Store inheritance information for new rel. */
@@ -3308,7 +3326,8 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 		case AT_SetRelOptions:	/* SET (...) */
 		case AT_ResetRelOptions:		/* RESET (...) */
 		case AT_ReplaceRelOptions:		/* reset them all, then set just these */
-			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX);
+			ATSimplePermissions(rel, ATT_TABLE | ATT_VIEW | ATT_MATVIEW |
+								ATT_INDEX | ATT_SEQUENCE);
 			/* This command never recurses */
 			/* No command-specific prep needed */
 			pass = AT_PASS_MISC;
@@ -4308,6 +4327,9 @@ ATSimplePermissions(Relation rel, int allowed_targets)
 		case RELKIND_FOREIGN_TABLE:
 			actual_target = ATT_FOREIGN_TABLE;
 			break;
+		case RELKIND_SEQUENCE:
+			actual_target = ATT_SEQUENCE;
+			break;
 		default:
 			actual_target = 0;
 			break;
@@ -4351,8 +4373,8 @@ ATWrongRelkindError(Relation rel, int allowed_targets)
 		case ATT_TABLE | ATT_VIEW | ATT_FOREIGN_TABLE:
 			msg = _("\"%s\" is not a table, view, or foreign table");
 			break;
-		case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX:
-			msg = _("\"%s\" is not a table, view, materialized view, or index");
+		case ATT_TABLE | ATT_VIEW | ATT_MATVIEW | ATT_INDEX | ATT_SEQUENCE:
+			msg = _("\"%s\" is not a table, view, materialized view, index or sequence");
 			break;
 		case ATT_TABLE | ATT_MATVIEW:
 			msg = _("\"%s\" is not a table or materialized view");
@@ -9403,12 +9425,15 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 			(void) view_reloptions(newOptions, true);
 			break;
 		case RELKIND_INDEX:
-			(void) index_reloptions(rel->rd_amroutine->amoptions, newOptions, true);
+			(void) am_reloptions(rel->rd_amroutine->amoptions, newOptions, true);
+			break;
+		case RELKIND_SEQUENCE:
+			(void) am_reloptions(rel->rd_seqamroutine->amoptions, newOptions, true);
 			break;
 		default:
 			ereport(ERROR,
 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
-					 errmsg("\"%s\" is not a table, view, materialized view, index, or TOAST table",
+					 errmsg("\"%s\" is not a table, view, materialized view, index, sequence, or TOAST table",
 							RelationGetRelationName(rel))));
 			break;
 	}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 3de29b7..7aab5ab 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -2116,7 +2116,8 @@ DefineCompositeType(RangeVar *typevar, List *coldeflist)
 	/*
 	 * Finally create the relation.  This also creates the type.
 	 */
-	DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, &address);
+	DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid, InvalidOid,
+				   &address);
 
 	return address;
 }
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index e9d9ba2..ca0f481 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -240,7 +240,8 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
 		 * existing view, so we don't need more code to complain if "replace"
 		 * is false).
 		 */
-		address = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid, NULL);
+		address = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid,
+								 InvalidOid, NULL);
 		Assert(address.objectId != InvalidOid);
 		return address;
 	}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f4e4a91..9ea0eb8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3565,7 +3565,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;
@@ -3578,7 +3580,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 854c062..5972ca6 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1627,7 +1627,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;
@@ -1638,7 +1640,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 1273352..75af985 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -310,7 +310,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <list>	event_trigger_when_list event_trigger_value_list
 %type <defelt>	event_trigger_when_item
-%type <chr>		enable_trigger
+%type <chr>		enable_trigger am_type
 
 %type <str>		copy_file_name
 				database_name access_method_clause access_method attr_name
@@ -605,7 +605,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
 	LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED LOGGED
 
-	MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P MOVE
+	MAPPING MATCH MATERIALIZED MAXVALUE METHOD MINUTE_P MINVALUE MODE MONTH_P
+	MOVE
 
 	NAME_P NAMES NATIONAL NATURAL NCHAR NEXT NO NONE
 	NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
@@ -3587,7 +3588,33 @@ CreateSeqStmt:
 					CreateSeqStmt *n = makeNode(CreateSeqStmt);
 					$4->relpersistence = $2;
 					n->sequence = $4;
+					n->accessMethod = NULL;
 					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;
@@ -3609,7 +3636,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;
 				}
@@ -3617,11 +3668,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; }
@@ -3680,7 +3754,7 @@ SeqOptElem: CACHE NumericOnly
 				{
 					$$ = makeDefElem("restart", (Node *)$3);
 				}
-		;
+			;
 
 opt_by:		BY				{}
 			| /* empty */	{}
@@ -4715,16 +4789,21 @@ row_security_cmd:
  *
  *****************************************************************************/
 
-CreateAmStmt: CREATE ACCESS METHOD name TYPE_P INDEX HANDLER handler_name
+CreateAmStmt: CREATE ACCESS METHOD name TYPE_P am_type HANDLER handler_name
 				{
 					CreateAmStmt *n = makeNode(CreateAmStmt);
 					n->amname = $4;
 					n->handler_name = $8;
-					n->amtype = AMTYPE_INDEX;
+					n->amtype = $6;
 					$$ = (Node *) n;
 				}
 		;
 
+am_type:
+			INDEX		{ $$ = AMTYPE_INDEX; }
+		|	SEQUENCE	{ $$ = AMTYPE_SEQUENCE; }
+		;
+
 /*****************************************************************************
  *
  *		QUERIES :
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 6528494..509fa32 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -29,6 +29,7 @@
 #include "access/amapi.h"
 #include "access/htup_details.h"
 #include "access/reloptions.h"
+#include "access/seqamapi.h"
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
@@ -456,6 +457,8 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
 		seqstmt = makeNode(CreateSeqStmt);
 		seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
 		seqstmt->options = NIL;
+		seqstmt->amoptions = NIL;
+		seqstmt->accessMethod = NULL;
 
 		/*
 		 * If this is ALTER ADD COLUMN, make sure the sequence will be owned
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 4d0aac9..8b95577 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -965,7 +965,8 @@ ProcessUtilitySlow(Node *parsetree,
 							/* Create the table itself */
 							address = DefineRelation((CreateStmt *) stmt,
 													 RELKIND_RELATION,
-													 InvalidOid, NULL);
+													 InvalidOid, InvalidOid,
+													 NULL);
 							EventTriggerCollectSimpleCommand(address,
 															 secondaryObject,
 															 stmt);
@@ -998,7 +999,8 @@ ProcessUtilitySlow(Node *parsetree,
 							/* Create the table itself */
 							address = DefineRelation((CreateStmt *) stmt,
 													 RELKIND_FOREIGN_TABLE,
-													 InvalidOid, NULL);
+													 InvalidOid, InvalidOid,
+													 NULL);
 							CreateForeignTable((CreateForeignTableStmt *) stmt,
 											   address.objectId);
 							EventTriggerCollectSimpleCommand(address,
diff --git a/src/backend/utils/adt/pseudotypes.c b/src/backend/utils/adt/pseudotypes.c
index dd447cf..6c1456e 100644
--- a/src/backend/utils/adt/pseudotypes.c
+++ b/src/backend/utils/adt/pseudotypes.c
@@ -399,6 +399,31 @@ index_am_handler_out(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();			/* keep compiler quiet */
 }
 
+/*
+ * seq_am_handler_int		- input routine for pseudo-type SEQ_AM_HANDLER.
+ */
+Datum
+seq_am_handler_in(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot accept a value of type seq_am_handler")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
+
+/*
+ * seq_am_handler_out		- output routine for pseudo-type SEQ_AM_HANDLER.
+ */
+Datum
+seq_am_handler_out(PG_FUNCTION_ARGS)
+{
+	ereport(ERROR,
+			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+			 errmsg("cannot display a value of type seq_am_handler")));
+
+	PG_RETURN_VOID();			/* keep compiler quiet */
+}
 
 /*
  * tsm_handler_in		- input routine for pseudo-type TSM_HANDLER.
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 130c06d..b9686da 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -33,6 +33,7 @@
 #include "access/htup_details.h"
 #include "access/multixact.h"
 #include "access/reloptions.h"
+#include "access/seqamapi.h"
 #include "access/sysattr.h"
 #include "access/xact.h"
 #include "access/xlog.h"
@@ -260,6 +261,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);
@@ -424,6 +426,7 @@ static void
 RelationParseRelOptions(Relation relation, HeapTuple tuple)
 {
 	bytea	   *options;
+	amoptions_function	amoptions = NULL;
 
 	relation->rd_options = NULL;
 
@@ -432,10 +435,15 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
-		case RELKIND_INDEX:
 		case RELKIND_VIEW:
 		case RELKIND_MATVIEW:
 			break;
+		case RELKIND_INDEX:
+			amoptions = relation->rd_amroutine->amoptions;
+			break;
+		case RELKIND_SEQUENCE:
+			amoptions = relation->rd_seqamroutine->amoptions;
+			break;
 		default:
 			return;
 	}
@@ -447,8 +455,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 	 */
 	options = extractRelOptions(tuple,
 								GetPgClassDescriptor(),
-								relation->rd_rel->relkind == RELKIND_INDEX ?
-								relation->rd_amroutine->amoptions : NULL);
+								amoptions);
 
 	/*
 	 * Copy parsed data into CacheMemoryContext.  To guard against the
@@ -1049,11 +1056,14 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
 	else
 		relation->rd_rsdesc = NULL;
 
-	/*
-	 * if it's an index, initialize index-related information
-	 */
-	if (OidIsValid(relation->rd_rel->relam))
+	/* if it's an index, initialize index-related information */
+	if (relation->rd_rel->relkind == RELKIND_INDEX &&
+		OidIsValid(relation->rd_rel->relam))
 		RelationInitIndexAccessInfo(relation);
+	/* same for sequences */
+	else if (relation->rd_rel->relkind == RELKIND_SEQUENCE &&
+			 OidIsValid(relation->rd_rel->relam))
+		RelationInitSequenceAccessInfo(relation);
 
 	/* extract reloptions if any */
 	RelationParseRelOptions(relation, pg_class_tuple);
@@ -1555,6 +1565,34 @@ LookupOpclassInfo(Oid operatorClassOid,
 	return opcentry;
 }
 
+/*
+ * Initialize sequence-access-method support data for a sequence relation
+ */
+static void
+RelationInitSequenceAccessInfo(Relation relation)
+{
+	HeapTuple	tuple;
+	Form_pg_am	aform;
+	SeqAmRoutine	   *result, *tmp;
+
+	/*
+	 * Look up the index's access method, save the OID of its handler function
+	 */
+	tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for access method %u",
+			 relation->rd_rel->relam);
+	aform = (Form_pg_am) GETSTRUCT(tuple);
+	Assert(aform->amtype == AMTYPE_SEQUENCE);
+	relation->rd_amhandler = aform->amhandler;
+	ReleaseSysCache(tuple);
+
+	result = (SeqAmRoutine *) MemoryContextAlloc(CacheMemoryContext,
+												 sizeof(SeqAmRoutine));
+	tmp = GetSeqAmRoutine(relation->rd_amhandler);
+	memcpy(result, tmp, sizeof(SeqAmRoutine));
+	relation->rd_seqamroutine = result;
+}
 
 /*
  *		formrdesc
@@ -4885,6 +4923,7 @@ load_relcache_init_file(bool shared)
 			Assert(rel->rd_supportinfo == NULL);
 			Assert(rel->rd_indoption == NULL);
 			Assert(rel->rd_indcollation == NULL);
+			Assert(rel->rd_seqamroutine == NULL);
 		}
 
 		/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 06cb166..fa4d39d 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -28,6 +28,7 @@
 
 #include "access/commit_ts.h"
 #include "access/gin.h"
+#include "access/seqamapi.h"
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 454225d..6e6f5a0 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -4747,6 +4747,7 @@ getTables(Archive *fout, int *numTables)
 	int			i_relreplident;
 	int			i_owning_tab;
 	int			i_owning_col;
+	int			i_relam;
 	int			i_reltablespace;
 	int			i_reloptions;
 	int			i_checkoption;
@@ -4798,6 +4799,7 @@ getTables(Archive *fout, int *numTables)
 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
@@ -4840,6 +4842,7 @@ getTables(Archive *fout, int *numTables)
 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
@@ -4882,6 +4885,7 @@ getTables(Archive *fout, int *numTables)
 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
@@ -4924,6 +4928,7 @@ getTables(Archive *fout, int *numTables)
 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
 						  "tc.reloptions AS toast_reloptions "
@@ -4964,6 +4969,7 @@ getTables(Archive *fout, int *numTables)
 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
 						  "tc.reloptions AS toast_reloptions "
@@ -5003,6 +5009,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
 						  "tc.reloptions AS toast_reloptions "
@@ -5042,6 +5049,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "c.reloptions AS reloptions, "
 						  "NULL AS toast_reloptions "
@@ -5081,6 +5089,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
 						  "NULL AS reloptions, "
 						  "NULL AS toast_reloptions "
@@ -5119,6 +5128,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "d.refobjid AS owning_tab, "
 						  "d.refobjsubid AS owning_col, "
+						  "c.relam, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
 						  "NULL AS toast_reloptions "
@@ -5153,6 +5163,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "NULL::oid AS owning_tab, "
 						  "NULL::int4 AS owning_col, "
+						  "c.relam, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
 						  "NULL AS toast_reloptions "
@@ -5182,6 +5193,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "NULL::oid AS owning_tab, "
 						  "NULL::int4 AS owning_col, "
+						  "c.relam, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
 						  "NULL AS toast_reloptions "
@@ -5221,6 +5233,7 @@ getTables(Archive *fout, int *numTables)
 						  "NULL AS reloftype, "
 						  "NULL::oid AS owning_tab, "
 						  "NULL::int4 AS owning_col, "
+						  "c.relam, "
 						  "NULL AS reltablespace, "
 						  "NULL AS reloptions, "
 						  "NULL AS toast_reloptions "
@@ -5274,6 +5287,7 @@ getTables(Archive *fout, int *numTables)
 	i_relpages = PQfnumber(res, "relpages");
 	i_owning_tab = PQfnumber(res, "owning_tab");
 	i_owning_col = PQfnumber(res, "owning_col");
+	i_relam = PQfnumber(res, "relam");
 	i_reltablespace = PQfnumber(res, "reltablespace");
 	i_reloptions = PQfnumber(res, "reloptions");
 	i_checkoption = PQfnumber(res, "checkoption");
@@ -5339,6 +5353,10 @@ getTables(Archive *fout, int *numTables)
 			tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
 			tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
 		}
+		if (PQgetisnull(res, i, i_relam))
+			tblinfo[i].relam = InvalidOid;
+		else
+			tblinfo[i].relam = atoi(PQgetvalue(res, i, i_relam));
 		tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
 		tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
 		if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
@@ -11577,6 +11595,9 @@ dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
 		case AMTYPE_INDEX:
 			appendPQExpBuffer(q, "TYPE INDEX ");
 			break;
+		case AMTYPE_SEQUENCE:
+			appendPQExpBuffer(q, "TYPE SEQUENCE ");
+			break;
 		default:
 			write_msg(NULL, "WARNING: invalid type %c of access method %s\n",
 					  aminfo->amtype, qamname);
@@ -15317,7 +15338,8 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 			   *incby,
 			   *maxv = NULL,
 			   *minv = NULL,
-			   *cache;
+			   *cache,
+			   *amname = NULL;
 	char		bufm[100],
 				bufx[100];
 	bool		cycled;
@@ -15334,8 +15356,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 	if (fout->remoteVersion >= 80400)
 	{
 		appendPQExpBuffer(query,
-						  "SELECT sequence_name, "
-						  "start_value, increment_by, "
+						  "SELECT start_value, increment_by, "
 				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
 				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
 						  "     ELSE max_value "
@@ -15351,8 +15372,7 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 	else
 	{
 		appendPQExpBuffer(query,
-						  "SELECT sequence_name, "
-						  "0 AS start_value, increment_by, "
+						  "SELECT 0 AS start_value, increment_by, "
 				   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
 				   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
 						  "     ELSE max_value "
@@ -15377,24 +15397,40 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 		exit_nicely(1);
 	}
 
-	/* Disable this check: it fails if sequence has been renamed */
-#ifdef NOT_USED
-	if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
+	startv = PQgetvalue(res, 0, 0);
+	incby = PQgetvalue(res, 0, 1);
+	if (!PQgetisnull(res, 0, 2))
+		maxv = PQgetvalue(res, 0, 2);
+	if (!PQgetisnull(res, 0, 3))
+		minv = PQgetvalue(res, 0, 3);
+	cache = PQgetvalue(res, 0, 4);
+	cycled = (strcmp(PQgetvalue(res, 0, 5), "t") == 0);
+
+	/* 9.6 adds sequence access methods */
+	if (fout->remoteVersion >= 90600)
 	{
-		write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
-				  tbinfo->dobj.name, PQgetvalue(res, 0, 0));
-		exit_nicely(1);
-	}
-#endif
+		PGresult   *res2;
 
-	startv = PQgetvalue(res, 0, 1);
-	incby = PQgetvalue(res, 0, 2);
-	if (!PQgetisnull(res, 0, 3))
-		maxv = PQgetvalue(res, 0, 3);
-	if (!PQgetisnull(res, 0, 4))
-		minv = PQgetvalue(res, 0, 4);
-	cache = PQgetvalue(res, 0, 5);
-	cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
+		printfPQExpBuffer(query, "SELECT a.amname\n"
+								 "FROM pg_catalog.pg_am a, pg_catalog.pg_class c\n"
+								 "WHERE c.relam = a.oid AND c.oid = %u",
+						  tbinfo->dobj.catId.oid);
+
+		res2 = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+		if (PQntuples(res2) != 1)
+		{
+			write_msg(NULL, ngettext("query to get access method of sequence \"%s\" returned %d row (expected 1)\n",
+									 "query to get access method of sequence \"%s\" returned %d rows (expected 1)\n",
+									 PQntuples(res2)),
+					  tbinfo->dobj.name, PQntuples(res2));
+			exit_nicely(1);
+		}
+
+		amname = pg_strdup(PQgetvalue(res2, 0, 0));
+
+		PQclear(res2);
+	}
 
 	/*
 	 * DROP must be fully qualified in case same name appears in pg_catalog
@@ -15437,6 +15473,13 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 					  "    CACHE %s%s",
 					  cache, (cycled ? "\n    CYCLE" : ""));
 
+	/*
+	 * Only produce using when it makes sense,
+	 * this helps with backwards compatibility.
+	 */
+	if (amname)
+		appendPQExpBuffer(query, "\n    USING %s", fmtId(amname));
+
 	appendPQExpBufferStr(query, ";\n");
 
 	appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
@@ -15503,6 +15546,9 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
 				 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
 				 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
 
+	if (amname)
+		free(amname);
+
 	PQclear(res);
 
 	destroyPQExpBuffer(query);
@@ -15519,16 +15565,23 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 {
 	TableInfo  *tbinfo = tdinfo->tdtable;
 	PGresult   *res;
-	char	   *last;
-	bool		called;
 	PQExpBuffer query = createPQExpBuffer();
 
 	/* Make sure we are in proper schema */
 	selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
 
-	appendPQExpBuffer(query,
-					  "SELECT last_value, is_called FROM %s",
-					  fmtId(tbinfo->dobj.name));
+	/* On 9.6 there is special interface for dumping sequences */
+	if (fout->remoteVersion >= 90600)
+	{
+		appendPQExpBuffer(query,
+						  "SELECT quote_literal(pg_catalog.pg_sequence_get_state(");
+		appendStringLiteralAH(query, tbinfo->dobj.name, fout);
+		appendPQExpBuffer(query, "))");
+	}
+	else
+		appendPQExpBuffer(query,
+						  "SELECT last_value, is_called FROM %s",
+						  fmtId(tbinfo->dobj.name));
 
 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
 
@@ -15541,14 +15594,27 @@ dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
 		exit_nicely(1);
 	}
 
-	last = PQgetvalue(res, 0, 0);
-	called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
-
 	resetPQExpBuffer(query);
-	appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
-	appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
-	appendPQExpBuffer(query, ", %s, %s);\n",
-					  last, (called ? "true" : "false"));
+
+	if (fout->remoteVersion >= 90600)
+	{
+		char   *state = PQgetvalue(res, 0, 0);
+
+		appendPQExpBufferStr(query, "SELECT pg_catalog.pg_sequence_set_state(");
+		appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+		/* The state got quote in the SELECT. */
+		appendPQExpBuffer(query, ", %s);\n", state);
+	}
+	else
+	{
+		char   *last = PQgetvalue(res, 0, 0);
+		bool	called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
+
+		appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
+		appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
+		appendPQExpBuffer(query, ", %s, %s);\n",
+						  last, (called ? "true" : "false"));
+	}
 
 	ArchiveEntry(fout, nilCatalogId, createDumpId(),
 				 tbinfo->dobj.name,
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index c02c536..c62abcc 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -231,6 +231,7 @@ typedef struct _tableInfo
 	/* these two are set only if table is a sequence owned by a column: */
 	Oid			owning_tab;		/* OID of table owning sequence */
 	int			owning_col;		/* attr # of column owning sequence */
+	int			relam;			/* access method (from pg_class) */
 	int			relpages;		/* table's size in pages (from pg_class) */
 
 	bool		interesting;	/* true if need to collect more data */
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 7b2f4e6..ac85da3 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1403,30 +1403,6 @@ describeOneTableDetails(const char *schemaname,
 	res = NULL;
 
 	/*
-	 * If it's a sequence, fetch its values and store into an array that will
-	 * be used later.
-	 */
-	if (tableinfo.relkind == 'S')
-	{
-		printfPQExpBuffer(&buf, "SELECT * FROM %s", fmtId(schemaname));
-		/* must be separate because fmtId isn't reentrant */
-		appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
-
-		res = PSQLexec(buf.data);
-		if (!res)
-			goto error_return;
-
-		seq_values = pg_malloc((PQnfields(res) + 1) * sizeof(*seq_values));
-
-		for (i = 0; i < PQnfields(res); i++)
-			seq_values[i] = pg_strdup(PQgetvalue(res, 0, i));
-		seq_values[i] = NULL;
-
-		PQclear(res);
-		res = NULL;
-	}
-
-	/*
 	 * Get column info
 	 *
 	 * You need to modify value of "firstvcol" which will be defined below if
@@ -1470,13 +1446,55 @@ describeOneTableDetails(const char *schemaname,
 
 	appendPQExpBufferStr(&buf, "\nFROM pg_catalog.pg_attribute a");
 	appendPQExpBuffer(&buf, "\nWHERE a.attrelid = '%s' AND a.attnum > 0 AND NOT a.attisdropped", oid);
+
+	/*
+	 * For sequence, fetch only the common column unless verbose was specified.
+	 * Note that this is change from pre9.5 versions.
+	 */
+	if (tableinfo.relkind == 'S')
+		appendPQExpBufferStr(&buf, " AND attname <> 'amdata'");
+
 	appendPQExpBufferStr(&buf, "\nORDER BY a.attnum;");
 
+
 	res = PSQLexec(buf.data);
 	if (!res)
 		goto error_return;
 	numrows = PQntuples(res);
 
+	/*
+	 * If it's a sequence, fetch its values and store into an array that will
+	 * be used later.
+	 */
+	if (tableinfo.relkind == 'S')
+	{
+		PGresult   *result;
+
+		/*
+		 * Use column names from the column info query, to automatically skip
+		 * unwanted columns.
+		 */
+		printfPQExpBuffer(&buf, "SELECT ");
+		for (i = 0; i < numrows; i++)
+			appendPQExpBuffer(&buf, i > 0 ? ", %s" : "%s", fmtId(PQgetvalue(res, i, 0)));
+		appendPQExpBuffer(&buf, " FROM %s",
+						  fmtId(schemaname));
+		/* must be separate because fmtId isn't reentrant */
+		appendPQExpBuffer(&buf, ".%s;", fmtId(relationname));
+
+		result = PSQLexec(buf.data);
+		if (!result)
+			goto error_return;
+
+		seq_values = pg_malloc((PQnfields(result) + 1) * sizeof(*seq_values));
+
+		for (i = 0; i < PQnfields(result); i++)
+			seq_values[i] = pg_strdup(PQgetvalue(result, 0, i));
+		seq_values[i] = NULL;
+
+		PQclear(result);
+	}
+
 	/* Make title */
 	switch (tableinfo.relkind)
 	{
@@ -1805,6 +1823,8 @@ describeOneTableDetails(const char *schemaname,
 						  oid);
 
 		result = PSQLexec(buf.data);
+
+		/* Same logic as above, only print result when we get one row. */
 		if (!result)
 			goto error_return;
 		else if (PQntuples(result) == 1)
@@ -1814,12 +1834,56 @@ describeOneTableDetails(const char *schemaname,
 			printTableAddFooter(&cont, buf.data);
 		}
 
+		PQclear(result);
+
+		/* Get the Access Method name for the sequence */
+		printfPQExpBuffer(&buf, "SELECT a.amname\n"
+								"FROM pg_catalog.pg_am a, pg_catalog.pg_class c\n"
+								"WHERE c.relam = a.oid AND c.oid = %s", oid);
+
+		result = PSQLexec(buf.data);
+
 		/*
 		 * If we get no rows back, don't show anything (obviously). We should
 		 * never get more than one row back, but if we do, just ignore it and
 		 * don't print anything.
 		 */
+		if (!result)
+			goto error_return;
+		else if (PQntuples(result) == 1)
+		{
+			printfPQExpBuffer(&buf, _("Access Method: %s"),
+							  PQgetvalue(result, 0, 0));
+			printTableAddFooter(&cont, buf.data);
+		}
+
 		PQclear(result);
+
+		if (verbose)
+		{
+			/* Get the Access Method state */
+			printfPQExpBuffer(&buf,
+							  "SELECT pg_catalog.pg_sequence_get_state('%s');",
+							  oid);
+
+			result = PSQLexec(buf.data);
+
+			/*
+			 * If we get no rows back, don't show anything (obviously). We should
+			 * never get more than one row back, but if we do, just ignore it and
+			 * don't print anything.
+			 */
+			if (!result)
+				goto error_return;
+			else if (PQntuples(result) == 1)
+			{
+				printfPQExpBuffer(&buf, _("Access Method State: %s"),
+								  PQgetvalue(result, 0, 0));
+				printTableAddFooter(&cont, buf.data);
+			}
+
+			PQclear(result);
+		}
 	}
 	else if (tableinfo.relkind == 'r' || tableinfo.relkind == 'm' ||
 			 tableinfo.relkind == 'f')
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 469ac67..69135aa 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -273,7 +273,7 @@ extern bytea *default_reloptions(Datum reloptions, bool validate,
 				   relopt_kind kind);
 extern bytea *heap_reloptions(char relkind, Datum reloptions, bool validate);
 extern bytea *view_reloptions(Datum reloptions, bool validate);
-extern bytea *index_reloptions(amoptions_function amoptions, Datum reloptions,
+extern bytea *am_reloptions(amoptions_function 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/seqamapi.h b/src/include/access/seqamapi.h
new file mode 100644
index 0000000..a4c826a
--- /dev/null
+++ b/src/include/access/seqamapi.h
@@ -0,0 +1,109 @@
+/*-------------------------------------------------------------------------
+ *
+ * seqamapi.h
+ *	  Public header file for Sequence access method.
+ *
+ *
+ * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/access/seqamapi.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef SEQAMAPI_H
+#define SEQAMAPI_H
+
+#include "fmgr.h"
+
+#include "access/htup.h"
+#include "commands/sequence.h"
+#include "utils/relcache.h"
+#include "storage/buf.h"
+#include "storage/bufpage.h"
+
+struct SequenceHandle;
+typedef struct SequenceHandle SequenceHandle;
+
+typedef bytea * (*ParseRelOptions_function) (Datum reloptions,
+											 bool validate);
+
+typedef Datum (*SeqAMInit_function) (Relation seqrel,
+									 Form_pg_sequence seq,
+									 int64 restart_value,
+									 bool restart_requested,
+									 bool is_init);
+
+typedef int64 (*SeqAMAlloc_function) (Relation seqrel,
+									  SequenceHandle *seqh,
+									  int64 nrequested,
+									  int64 *last);
+
+typedef void (*SeqAMSetval_function) (Relation seqrel,
+									  SequenceHandle *seqh,
+									  int64 new_value);
+
+typedef Datum (*SeqAMGetState_function) (Relation seqrel,
+										 SequenceHandle *seqh);
+typedef void (*SeqAMSetState_function) (Relation seqrel, SequenceHandle *seqh,
+										Datum amstate);
+
+typedef struct SeqAmRoutine
+{
+	NodeTag		type;
+
+	/* Custom columns needed by the AM */
+	Oid			StateTypeOid;
+
+	/* Function for parsing reloptions */
+	ParseRelOptions_function	amoptions;
+
+	/* Initialization */
+	SeqAMInit_function			Init;
+
+	/* nextval handler */
+	SeqAMAlloc_function			Alloc;
+
+	/* State manipulation functions */
+	SeqAMSetval_function		Setval;
+	SeqAMGetState_function		GetState;
+	SeqAMSetState_function		SetState;
+} SeqAmRoutine;
+
+extern SeqAmRoutine *GetSeqAmRoutine(Oid seqamhandler);
+extern SeqAmRoutine *GetSeqAmRoutineByAMId(Oid amoid);
+extern SeqAmRoutine *GetSeqAmRoutineForRelation(Relation relation);
+extern void ValidateSeqAmRoutine(SeqAmRoutine *routine);
+
+extern void sequence_open(Oid seqrelid, SequenceHandle *seqh);
+extern void sequence_close(SequenceHandle *seqh);
+extern Form_pg_sequence sequence_read_options(SequenceHandle *seqh);
+extern Datum sequence_read_state(SequenceHandle *seqh);
+extern void sequence_start_update(SequenceHandle *seqh, bool dowal);
+extern void sequence_save_state(SequenceHandle *seqh, Datum seqstate,
+								bool dowal);
+extern void sequence_finish_update(SequenceHandle *seqh);
+extern void sequence_release_tuple(SequenceHandle *seqh);
+extern bool sequence_needs_wal(SequenceHandle *seqh);
+
+extern int64 sequence_increment(Relation seqrel, int64 *value, int64 incnum,
+								int64 minv, int64 maxv, int64 incby,
+								bool is_cycled, bool report_errors);
+extern void sequence_check_range(int64 value, int64 min_value,
+								 int64 max_value, const char *valname);
+extern int64 sequence_get_restart_value(List *options, int64 default_value,
+										bool *found);
+
+/* We need this public for serval3 */
+typedef struct LocalSequenceState
+{
+	int64   last_value;
+	int32	log_cnt;
+	bool	is_called;
+} LocalSequenceState;
+
+extern Datum seqam_local_state_in(PG_FUNCTION_ARGS);
+extern Datum seqam_local_state_out(PG_FUNCTION_ARGS);
+extern Datum seqam_local_handler(PG_FUNCTION_ARGS);
+
+#endif   /* SEQAMAPI_H */
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index b80d8d8..d6b3cd7 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -71,6 +71,7 @@ extern Oid heap_create_with_catalog(const char *relname,
 						 bool use_user_acl,
 						 bool allow_system_table_mods,
 						 bool is_internal,
+						 Oid relam,
 						 ObjectAddress *typaddress);
 
 extern void heap_create_init_fork(Relation rel);
diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h
index 1116923..9c615f7 100644
--- a/src/include/catalog/pg_am.h
+++ b/src/include/catalog/pg_am.h
@@ -59,6 +59,7 @@ typedef FormData_pg_am *Form_pg_am;
  * ----------------
  */
 #define AMTYPE_INDEX					'i'		/* index access method */
+#define	AMTYPE_SEQUENCE					'S'		/* sequence access method */
 
 /* ----------------
  *		initial contents of pg_am
@@ -84,4 +85,8 @@ DATA(insert OID = 3580 (  brin		brinhandler i ));
 DESCR("block range index (BRIN) access method");
 #define BRIN_AM_OID 3580
 
+DATA(insert OID = 6023 (  local		seqam_local_handler	S ));
+DESCR("local sequence access method");
+#define LOCAL_SEQAM_OID 6023
+
 #endif   /* PG_AM_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c86b920..54a712c 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1759,6 +1759,10 @@ DATA(insert OID = 1765 (  setval			PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 20
 DESCR("set sequence value and is_called status");
 DATA(insert OID = 3078 (  pg_sequence_parameters	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 1 0 2249 "26" "{26,20,20,20,20,16}" "{i,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option}" _null_ _null_ pg_sequence_parameters _null_ _null_ _null_));
 DESCR("sequence parameters, for use by information schema");
+DATA(insert OID = 3377 (  pg_sequence_get_state		PGNSP PGUID 12 1 0 0 0 f f f f t f v u 1 0 25 "2205" _null_ _null_ _null_ _null_ _null_ pg_sequence_get_state _null_ _null_ _null_ ));
+DESCR("Dump state of a sequence");
+DATA(insert OID = 3378 (  pg_sequence_set_state		PGNSP PGUID 12 1 0 0 0 f f f f t f v u 2 0 2278 "2205 25" _null_ _null_ _null_ _null_ _null_ pg_sequence_set_state _null_ _null_ _null_ ));
+DESCR("Restore state of a sequence");
 
 DATA(insert OID = 1579 (  varbit_in			PGNSP PGUID 12 1 0 0 0 f f f f t f i s 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ ));
 DESCR("I/O");
@@ -3690,6 +3694,10 @@ DATA(insert OID = 326  (  index_am_handler_in	PGNSP PGUID 12 1 0 0 0 f f f f f f
 DESCR("I/O");
 DATA(insert OID = 327  (  index_am_handler_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "325" _null_ _null_ _null_ _null_ _null_ index_am_handler_out _null_ _null_ _null_ ));
 DESCR("I/O");
+DATA(insert OID = 6021  (  seq_am_handler_in	PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 6020 "2275" _null_ _null_ _null_ _null_ _null_ seq_am_handler_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 6022 (  seq_am_handler_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "6020" _null_ _null_ _null_ _null_ _null_ seq_am_handler_out _null_ _null_ _null_ ));
+DESCR("I/O");
 DATA(insert OID = 3311 (  tsm_handler_in	PGNSP PGUID 12 1 0 0 0 f f f f f f i s 1 0 3310 "2275" _null_ _null_ _null_ _null_ _null_ tsm_handler_in _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 3312 (  tsm_handler_out	PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "3310" _null_ _null_ _null_ _null_ _null_ tsm_handler_out _null_ _null_ _null_ ));
@@ -3701,6 +3709,10 @@ DESCR("BERNOULLI tablesample method handler");
 DATA(insert OID = 3314 (  system			PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3310 "2281" _null_ _null_ _null_ _null_ _null_ tsm_system_handler _null_ _null_ _null_ ));
 DESCR("SYSTEM tablesample method handler");
 
+/* sequence access method handlers */
+DATA(insert OID = 6024 (  seqam_local_handler	   PGNSP PGUID 12 1 0 0 0 f f f f f f v s 1 0 6020 "2281" _null_ _null_ _null_ _null_ _null_ seqam_local_handler _null_ _null_ _null_ ));
+DESCR("Local SequenceAM handler");
+
 /* cryptographic */
 DATA(insert OID =  2311 (  md5	   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 25 "25" _null_ _null_ _null_ _null_ _null_ md5_text _null_ _null_ _null_ ));
 DESCR("MD5 hash");
@@ -5270,6 +5282,13 @@ DESCR("pg_controldata recovery state information as a function");
 DATA(insert OID = 3444 ( pg_control_init PGNSP PGUID 12 1 0 0 0 f f f f t f v s 0 0 2249 "" "{23,23,23,23,23,23,23,23,23,16,16,16,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{max_data_alignment,database_block_size,blocks_per_segment,wal_block_size,bytes_per_wal_segment,max_identifier_length,max_index_columns,max_toast_chunk_size,large_object_chunk_size,bigint_timestamps,float4_pass_by_value,float8_pass_by_value,data_page_checksum_version}" _null_ _null_ pg_control_init _null_ _null_ _null_ ));
 DESCR("pg_controldata init state information as a function");
 
+/* Sequence AM */
+DATA(insert OID = 6027 (  seqam_local_state_in		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 6025 "2275" _null_ _null_ _null_ _null_ _null_ seqam_local_state_in _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 6028 (  seqam_local_state_out		   PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 2275 "6025" _null_ _null_ _null_ _null_ _null_ seqam_local_state_out _null_ _null_ _null_ ));
+DESCR("I/O");
+
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 2c90b76..7f020fe 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -696,11 +696,18 @@ DATA(insert OID = 3115 ( fdw_handler	PGNSP PGUID  4 t p P f t \054 0 0 0 fdw_han
 #define FDW_HANDLEROID	3115
 DATA(insert OID = 325 ( index_am_handler	PGNSP PGUID  4 t p P f t \054 0 0 0 index_am_handler_in index_am_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 #define INDEX_AM_HANDLEROID	325
+DATA(insert OID = 6020 ( seq_am_handler	PGNSP PGUID  4 t p P f t \054 0 0 0 seq_am_handler_in seq_am_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+#define SEQ_AM_HANDLEROID	6020
 DATA(insert OID = 3310 ( tsm_handler	PGNSP PGUID  4 t p P f t \054 0 0 0 tsm_handler_in tsm_handler_out - - - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
 #define TSM_HANDLEROID	3310
 DATA(insert OID = 3831 ( anyrange		PGNSP PGUID  -1 f p P f t \054 0 0 0 anyrange_in anyrange_out - - - - - d x f 0 -1 0 0 _null_ _null_ _null_ ));
 #define ANYRANGEOID		3831
 
+/* Sequence AM composite types */
+DATA(insert OID = 6025 ( seqam_local_state	PGNSP PGUID 16 f b U f t \054 0 0 6026 seqam_local_state_in seqam_local_state_out - - - - - d p f 0 -1 0 0 _null_ _null_ _null_ ));
+#define SEQAMLOCALSTATEOID 6025
+DATA(insert OID = 6026 ( _seqam_local_state	PGNSP PGUID -1 f b A f t \054 0 6025 0 array_in array_out array_recv array_send - - array_typanalyze d x f 0 -1 0 0 _null_ _null_ _null_ ));
+
 
 /*
  * macros
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index b064eb4..c9bf431 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -139,6 +139,7 @@ extern Datum transformGenericOptions(Oid catalogId,
 extern ObjectAddress CreateAccessMethod(CreateAmStmt *stmt);
 extern void RemoveAccessMethodById(Oid amOid);
 extern Oid	get_index_am_oid(const char *amname, bool missing_ok);
+extern Oid	get_seq_am_oid(const char *amname, bool missing_ok);
 extern Oid	get_am_oid(const char *amname, bool missing_ok);
 extern char *get_am_name(Oid amOid);
 
diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h
index 6af60d8..2ff89b4 100644
--- a/src/include/commands/sequence.h
+++ b/src/include/commands/sequence.h
@@ -19,20 +19,17 @@
 #include "lib/stringinfo.h"
 #include "nodes/parsenodes.h"
 #include "storage/relfilenode.h"
-
+#include "access/htup_details.h"
 
 typedef struct FormData_pg_sequence
 {
-	NameData	sequence_name;
-	int64		last_value;
 	int64		start_value;
 	int64		increment_by;
 	int64		max_value;
 	int64		min_value;
 	int64		cache_value;
-	int64		log_cnt;
 	bool		is_cycled;
-	bool		is_called;
+	/* amstate follows */
 } FormData_pg_sequence;
 
 typedef FormData_pg_sequence *Form_pg_sequence;
@@ -41,19 +38,16 @@ typedef FormData_pg_sequence *Form_pg_sequence;
  * Columns of a sequence relation
  */
 
-#define SEQ_COL_NAME			1
-#define SEQ_COL_LASTVAL			2
-#define SEQ_COL_STARTVAL		3
-#define SEQ_COL_INCBY			4
-#define SEQ_COL_MAXVALUE		5
-#define SEQ_COL_MINVALUE		6
-#define SEQ_COL_CACHE			7
-#define SEQ_COL_LOG				8
-#define SEQ_COL_CYCLE			9
-#define SEQ_COL_CALLED			10
+#define SEQ_COL_STARTVAL		1
+#define SEQ_COL_INCBY			2
+#define SEQ_COL_MAXVALUE		3
+#define SEQ_COL_MINVALUE		4
+#define SEQ_COL_CACHE			5
+#define SEQ_COL_CYCLE			6
+#define SEQ_COL_AMSTATE			7
 
-#define SEQ_COL_FIRSTCOL		SEQ_COL_NAME
-#define SEQ_COL_LASTCOL			SEQ_COL_CALLED
+#define SEQ_COL_FIRSTCOL		SEQ_COL_STARTVAL
+#define SEQ_COL_LASTCOL			SEQ_COL_AMSTATE
 
 /* XLOG stuff */
 #define XLOG_SEQ_LOG			0x00
@@ -72,6 +66,8 @@ extern Datum setval3_oid(PG_FUNCTION_ARGS);
 extern Datum lastval(PG_FUNCTION_ARGS);
 
 extern Datum pg_sequence_parameters(PG_FUNCTION_ARGS);
+extern Datum pg_sequence_get_state(PG_FUNCTION_ARGS);
+extern Datum pg_sequence_set_state(PG_FUNCTION_ARGS);
 
 extern ObjectAddress DefineSequence(CreateSeqStmt *stmt);
 extern ObjectAddress AlterSequence(AlterSeqStmt *stmt);
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 7a770f4..1bceec8 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -23,7 +23,7 @@
 
 
 extern ObjectAddress DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
-			   ObjectAddress *typaddress);
+			   Oid relamid, ObjectAddress *typaddress);
 
 extern void RemoveRelations(DropStmt *drop);
 
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 734df77..752d3a1 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -477,6 +477,7 @@ typedef enum NodeTag
 	T_InlineCodeBlock,			/* in nodes/parsenodes.h */
 	T_FdwRoutine,				/* in foreign/fdwapi.h */
 	T_IndexAmRoutine,			/* in access/amapi.h */
+	T_SeqAmRoutine,				/* in access/seqamapi.h */
 	T_TsmRoutine				/* in access/tsmapi.h */
 } NodeTag;
 
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 8b958b4..859fbad 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2205,8 +2205,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;
 
@@ -2214,8 +2216,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/builtins.h b/src/include/utils/builtins.h
index d5c4b01..cf7e01b 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -587,6 +587,8 @@ extern Datum fdw_handler_in(PG_FUNCTION_ARGS);
 extern Datum fdw_handler_out(PG_FUNCTION_ARGS);
 extern Datum index_am_handler_in(PG_FUNCTION_ARGS);
 extern Datum index_am_handler_out(PG_FUNCTION_ARGS);
+extern Datum seq_am_handler_in(PG_FUNCTION_ARGS);
+extern Datum seq_am_handler_out(PG_FUNCTION_ARGS);
 extern Datum tsm_handler_in(PG_FUNCTION_ARGS);
 extern Datum tsm_handler_out(PG_FUNCTION_ARGS);
 extern Datum internal_in(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index f2bebf2..4fe7e52 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -106,13 +106,18 @@ typedef struct RelationData
 	 */
 	bytea	   *rd_options;		/* parsed pg_class.reloptions */
 
+	Oid			rd_amhandler;	/* OID of access method's handler function */
+
+	/* These are non-NULL only for a sequence relation */
+	struct SeqAmRoutine *rd_seqamroutine;
+
 	/* These are non-NULL only for an index relation: */
 	Form_pg_index rd_index;		/* pg_index tuple describing this index */
 	/* use "struct" here to avoid needing to include htup.h: */
 	struct HeapTupleData *rd_indextuple;		/* all of pg_index tuple */
 
 	/*
-	 * index access support info (used only for an index relation)
+	 * index access support info (used only for index relations)
 	 *
 	 * Note: only default support procs for each opclass are cached, namely
 	 * those with lefttype and righttype equal to the opclass's opcintype. The
@@ -126,7 +131,6 @@ typedef struct RelationData
 	 * rd_indexcxt.  A relcache reset will include freeing that chunk and
 	 * setting rd_amcache = NULL.
 	 */
-	Oid			rd_amhandler;	/* OID of index AM's handler function */
 	MemoryContext rd_indexcxt;	/* private memory cxt for this stuff */
 	/* use "struct" here to avoid needing to include amapi.h: */
 	struct IndexAmRoutine *rd_amroutine;		/* index AM's API struct */
diff --git a/src/test/regress/expected/create_am.out b/src/test/regress/expected/create_am.out
index 47d6024..9242982 100644
--- a/src/test/regress/expected/create_am.out
+++ b/src/test/regress/expected/create_am.out
@@ -106,3 +106,22 @@ drop cascades to index grect2ind
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
+-- Checks for sequence access methods
+-- Create new sequence access method which uses standard local handler
+CREATE ACCESS METHOD local2 TYPE SEQUENCE HANDLER seqam_local_handler;
+-- Create and use sequence
+CREATE SEQUENCE test_seqam USING local2;
+SELECT nextval('test_seqam'::regclass);
+ nextval 
+---------
+       1
+(1 row)
+
+-- Try to drop and fail on dependency
+DROP ACCESS METHOD local2;
+ERROR:  cannot drop access method local2 because other objects depend on it
+DETAIL:  sequence test_seqam depends on access method local2
+HINT:  Use DROP ... CASCADE to drop the dependent objects too.
+-- And cleanup
+DROP SEQUENCE test_seqam;
+DROP ACCESS METHOD local2;
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index ae50c94..f1b1fc2 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -129,8 +129,9 @@ NOTICE:  view "v12_temp" will be a temporary view
 -- a view should also be temporary if it references a temporary sequence
 CREATE SEQUENCE seq1;
 CREATE TEMPORARY SEQUENCE seq1_temp;
-CREATE VIEW v9 AS SELECT seq1.is_called FROM seq1;
-CREATE VIEW v13_temp AS SELECT seq1_temp.is_called FROM seq1_temp;
+CREATE TYPE seqam_local_state_rec AS (last_value int8, is_called bool, log_cnt int4);
+CREATE VIEW v9 AS SELECT (seq1::text::seqam_local_state_rec).is_called FROM seq1;
+CREATE VIEW v13_temp AS SELECT (seq1_temp::text::seqam_local_state_rec).is_called FROM seq1_temp;
 NOTICE:  view "v13_temp" will be a temporary view
 SELECT relname FROM pg_class
     WHERE relname LIKE 'v_'
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index a8dc0c1..1c51a5e 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -1586,7 +1586,9 @@ WHERE p1.amhandler = 0;
 SELECT p1.oid, p1.amname, p2.oid, p2.proname
 FROM pg_am AS p1, pg_proc AS p2
 WHERE p2.oid = p1.amhandler AND
-    (p2.prorettype != 'index_am_handler'::regtype OR p2.proretset
+    (p2.prorettype NOT IN ('index_am_handler'::regtype,
+			               'seq_am_handler'::regtype)
+     OR p2.proretset
      OR p2.pronargs != 1
      OR p2.proargtypes[0] != 'internal'::regtype);
  oid | amname | oid | proname 
diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out
index 8783ca6..3a19cde 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -129,10 +129,10 @@ SELECT nextval('sequence_test'::regclass);
       33
 (1 row)
 
-SELECT setval('sequence_test'::text, 99, false);
- setval 
---------
-     99
+SELECT pg_sequence_set_state('sequence_test'::text, '(99,false)');
+ pg_sequence_set_state 
+-----------------------
+ 
 (1 row)
 
 SELECT nextval('sequence_test'::regclass);
@@ -153,10 +153,10 @@ SELECT nextval('sequence_test'::text);
       33
 (1 row)
 
-SELECT setval('sequence_test'::regclass, 99, false);
- setval 
---------
-     99
+SELECT pg_sequence_set_state('sequence_test'::regclass, '(99,false)');
+ pg_sequence_set_state 
+-----------------------
+ 
 (1 row)
 
 SELECT nextval('sequence_test'::text);
@@ -173,9 +173,9 @@ DROP SEQUENCE sequence_test;
 CREATE SEQUENCE foo_seq;
 ALTER TABLE foo_seq RENAME TO foo_seq_new;
 SELECT * FROM foo_seq_new;
- sequence_name | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
----------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
- foo_seq       |          1 |           1 |            1 | 9223372036854775807 |         1 |           1 |       0 | f         | f
+ start_value | increment_by |      max_value      | min_value | cache_value | is_cycled | amstate 
+-------------+--------------+---------------------+-----------+-------------+-----------+---------
+           1 |            1 | 9223372036854775807 |         1 |           1 | f         | (1,f,0)
 (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
+ start_value | increment_by |      max_value      | min_value | cache_value | is_cycled | amstate  
+-------------+--------------+---------------------+-----------+-------------+-----------+----------
+           1 |            1 | 9223372036854775807 |         1 |           1 | f         | (2,t,31)
 (1 row)
 
 DROP SEQUENCE foo_seq_new;
@@ -300,6 +300,13 @@ SELECT nextval('sequence_test2');
        5
 (1 row)
 
+-- Sequence Acess Method
+CREATE SEQUENCE myamseq USING local WITH (foo = 'bar');
+ERROR:  local sequence does not accept any storage parameters
+CREATE SEQUENCE myamseq USING local;
+ALTER SEQUENCE myamseq SET (foo = 'baz');
+ERROR:  local sequence does not accept any storage parameters
+DROP SEQUENCE myamseq;
 -- Information schema
 SELECT * FROM information_schema.sequences WHERE sequence_name IN
   ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index c5dfbb5..a30582e 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -86,55 +86,52 @@ SELECT table_name, column_name, is_updatable
   FROM information_schema.columns
  WHERE table_name LIKE E'r_\\_view%'
  ORDER BY table_name, ordinal_position;
- table_name |  column_name  | is_updatable 
-------------+---------------+--------------
- ro_view1   | a             | NO
- ro_view1   | b             | NO
- ro_view10  | a             | NO
- ro_view11  | a             | NO
- ro_view11  | b             | NO
- ro_view12  | a             | NO
- ro_view13  | a             | NO
- ro_view13  | b             | NO
- ro_view17  | a             | NO
- ro_view17  | b             | NO
- ro_view18  | a             | NO
- ro_view19  | sequence_name | NO
- ro_view19  | last_value    | NO
- ro_view19  | start_value   | NO
- ro_view19  | increment_by  | NO
- ro_view19  | max_value     | NO
- ro_view19  | min_value     | NO
- ro_view19  | cache_value   | NO
- ro_view19  | log_cnt       | NO
- ro_view19  | is_cycled     | NO
- ro_view19  | is_called     | NO
- ro_view2   | a             | NO
- ro_view2   | b             | NO
- ro_view20  | a             | NO
- ro_view20  | b             | NO
- ro_view20  | g             | NO
- ro_view3   | ?column?      | NO
- ro_view4   | count         | NO
- ro_view5   | a             | NO
- ro_view5   | rank          | NO
- ro_view6   | a             | NO
- ro_view6   | b             | NO
- ro_view7   | a             | NO
- ro_view7   | b             | NO
- ro_view8   | a             | NO
- ro_view8   | b             | NO
- ro_view9   | a             | NO
- ro_view9   | b             | NO
- rw_view14  | ctid          | NO
- rw_view14  | a             | YES
- rw_view14  | b             | YES
- rw_view15  | a             | YES
- rw_view15  | upper         | NO
- rw_view16  | a             | YES
- rw_view16  | b             | YES
- rw_view16  | aa            | YES
-(46 rows)
+ table_name | column_name  | is_updatable 
+------------+--------------+--------------
+ ro_view1   | a            | NO
+ ro_view1   | b            | NO
+ ro_view10  | a            | NO
+ ro_view11  | a            | NO
+ ro_view11  | b            | NO
+ ro_view12  | a            | NO
+ ro_view13  | a            | NO
+ ro_view13  | b            | NO
+ ro_view17  | a            | NO
+ ro_view17  | b            | NO
+ ro_view18  | a            | NO
+ ro_view19  | start_value  | NO
+ ro_view19  | increment_by | NO
+ ro_view19  | max_value    | NO
+ ro_view19  | min_value    | NO
+ ro_view19  | cache_value  | NO
+ ro_view19  | is_cycled    | NO
+ ro_view19  | amstate      | NO
+ ro_view2   | a            | NO
+ ro_view2   | b            | NO
+ ro_view20  | a            | NO
+ ro_view20  | b            | NO
+ ro_view20  | g            | NO
+ ro_view3   | ?column?     | NO
+ ro_view4   | count        | NO
+ ro_view5   | a            | NO
+ ro_view5   | rank         | NO
+ ro_view6   | a            | NO
+ ro_view6   | b            | NO
+ ro_view7   | a            | NO
+ ro_view7   | b            | NO
+ ro_view8   | a            | NO
+ ro_view8   | b            | NO
+ ro_view9   | a            | NO
+ ro_view9   | b            | NO
+ rw_view14  | ctid         | NO
+ rw_view14  | a            | YES
+ rw_view14  | b            | YES
+ rw_view15  | a            | YES
+ rw_view15  | upper        | NO
+ rw_view16  | a            | YES
+ rw_view16  | b            | YES
+ rw_view16  | aa           | YES
+(43 rows)
 
 -- Read-only views
 DELETE FROM ro_view1;
diff --git a/src/test/regress/sql/create_am.sql b/src/test/regress/sql/create_am.sql
index e2051c5..e811ea3 100644
--- a/src/test/regress/sql/create_am.sql
+++ b/src/test/regress/sql/create_am.sql
@@ -71,3 +71,19 @@ DROP ACCESS METHOD gist2 CASCADE;
 RESET enable_seqscan;
 RESET enable_indexscan;
 RESET enable_bitmapscan;
+
+-- Checks for sequence access methods
+
+-- Create new sequence access method which uses standard local handler
+CREATE ACCESS METHOD local2 TYPE SEQUENCE HANDLER seqam_local_handler;
+
+-- Create and use sequence
+CREATE SEQUENCE test_seqam USING local2;
+SELECT nextval('test_seqam'::regclass);
+
+-- Try to drop and fail on dependency
+DROP ACCESS METHOD local2;
+
+-- And cleanup
+DROP SEQUENCE test_seqam;
+DROP ACCESS METHOD local2;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 58d361d..e967fff 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -131,8 +131,9 @@ CREATE VIEW v12_temp AS SELECT true FROM v11_temp;
 -- a view should also be temporary if it references a temporary sequence
 CREATE SEQUENCE seq1;
 CREATE TEMPORARY SEQUENCE seq1_temp;
-CREATE VIEW v9 AS SELECT seq1.is_called FROM seq1;
-CREATE VIEW v13_temp AS SELECT seq1_temp.is_called FROM seq1_temp;
+CREATE TYPE seqam_local_state_rec AS (last_value int8, is_called bool, log_cnt int4);
+CREATE VIEW v9 AS SELECT (seq1::text::seqam_local_state_rec).is_called FROM seq1;
+CREATE VIEW v13_temp AS SELECT (seq1_temp::text::seqam_local_state_rec).is_called FROM seq1_temp;
 
 SELECT relname FROM pg_class
     WHERE relname LIKE 'v_'
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 6c9784a..6c44d70 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -1055,7 +1055,9 @@ WHERE p1.amhandler = 0;
 SELECT p1.oid, p1.amname, p2.oid, p2.proname
 FROM pg_am AS p1, pg_proc AS p2
 WHERE p2.oid = p1.amhandler AND
-    (p2.prorettype != 'index_am_handler'::regtype OR p2.proretset
+    (p2.prorettype NOT IN ('index_am_handler'::regtype,
+			               'seq_am_handler'::regtype)
+     OR p2.proretset
      OR p2.pronargs != 1
      OR p2.proargtypes[0] != 'internal'::regtype);
 
diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql
index 0dd653d..c2b1164 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -67,11 +67,11 @@ SELECT currval('sequence_test'::text);
 SELECT currval('sequence_test'::regclass);
 SELECT setval('sequence_test'::text, 32);
 SELECT nextval('sequence_test'::regclass);
-SELECT setval('sequence_test'::text, 99, false);
+SELECT pg_sequence_set_state('sequence_test'::text, '(99,false)');
 SELECT nextval('sequence_test'::regclass);
 SELECT setval('sequence_test'::regclass, 32);
 SELECT nextval('sequence_test'::text);
-SELECT setval('sequence_test'::regclass, 99, false);
+SELECT pg_sequence_set_state('sequence_test'::regclass, '(99,false)');
 SELECT nextval('sequence_test'::text);
 DISCARD SEQUENCES;
 SELECT currval('sequence_test'::regclass);
@@ -138,6 +138,12 @@ SELECT nextval('sequence_test2');
 SELECT nextval('sequence_test2');
 SELECT nextval('sequence_test2');
 
+-- Sequence Acess Method
+CREATE SEQUENCE myamseq USING local WITH (foo = 'bar');
+CREATE SEQUENCE myamseq USING local;
+ALTER SEQUENCE myamseq SET (foo = 'baz');
+DROP SEQUENCE myamseq;
+
 -- Information schema
 SELECT * FROM information_schema.sequences WHERE sequence_name IN
   ('sequence_test2', 'serialtest2_f2_seq', 'serialtest2_f3_seq',
-- 
1.9.1

