0002-seqam-DDL-WIP.patch
text/x-diff
Filename: 0002-seqam-DDL-WIP.patch
Type: text/x-diff
Part: 1
Message:
Re: Sequence Access Method WIP
Patch
Format: unified
Series: patch 0002
| File | + | − |
|---|---|---|
| doc/src/sgml/ref/allfiles.sgml | 2 | 0 |
| doc/src/sgml/ref/create_seqam.sgml | 174 | 0 |
| doc/src/sgml/ref/drop_seqam.sgml | 87 | 0 |
| doc/src/sgml/reference.sgml | 2 | 0 |
| src/backend/access/sequence/seqam.c | 329 | 0 |
| src/backend/catalog/dependency.c | 10 | 1 |
| src/backend/catalog/objectaddress.c | 65 | 1 |
| src/backend/commands/dropcmds.c | 4 | 0 |
| src/backend/commands/event_trigger.c | 3 | 0 |
| src/backend/commands/sequence.c | 17 | 0 |
| src/backend/parser/gram.y | 13 | 1 |
| src/backend/tcop/utility.c | 12 | 0 |
| src/include/access/seqam.h | 3 | 0 |
| src/include/catalog/dependency.h | 1 | 0 |
| src/include/catalog/pg_proc.h | 2 | 2 |
| src/include/nodes/parsenodes.h | 1 | 0 |
| src/include/parser/kwlist.h | 1 | 0 |
>From d540f119373728d81ebdc9cb8563fc288e6a94d2 Mon Sep 17 00:00:00 2001
From: Petr Jelinek <pjmodos@pjmodos.net>
Date: Thu, 8 Jan 2015 23:26:39 +0100
Subject: [PATCH 2/3] seqam DDL WIP
---
doc/src/sgml/ref/allfiles.sgml | 2 +
doc/src/sgml/ref/create_seqam.sgml | 174 ++++++++++++++++++
doc/src/sgml/ref/drop_seqam.sgml | 87 +++++++++
doc/src/sgml/reference.sgml | 2 +
src/backend/access/sequence/seqam.c | 329 +++++++++++++++++++++++++++++++++++
src/backend/catalog/dependency.c | 11 +-
src/backend/catalog/objectaddress.c | 66 ++++++-
src/backend/commands/dropcmds.c | 4 +
src/backend/commands/event_trigger.c | 3 +
src/backend/commands/sequence.c | 17 ++
src/backend/parser/gram.y | 14 +-
src/backend/tcop/utility.c | 12 ++
src/include/access/seqam.h | 3 +
src/include/catalog/dependency.h | 1 +
src/include/catalog/pg_proc.h | 4 +-
src/include/nodes/parsenodes.h | 1 +
src/include/parser/kwlist.h | 1 +
17 files changed, 726 insertions(+), 5 deletions(-)
create mode 100644 doc/src/sgml/ref/create_seqam.sgml
create mode 100644 doc/src/sgml/ref/drop_seqam.sgml
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index 7aa3128..2e4a250 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -74,6 +74,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY createRole SYSTEM "create_role.sgml">
<!ENTITY createRule SYSTEM "create_rule.sgml">
<!ENTITY createSchema SYSTEM "create_schema.sgml">
+<!ENTITY createSeqAM SYSTEM "create_seqam.sgml">
<!ENTITY createSequence SYSTEM "create_sequence.sgml">
<!ENTITY createServer SYSTEM "create_server.sgml">
<!ENTITY createTable SYSTEM "create_table.sgml">
@@ -116,6 +117,7 @@ Complete list of usable sgml source files in this directory.
<!ENTITY dropRole SYSTEM "drop_role.sgml">
<!ENTITY dropRule SYSTEM "drop_rule.sgml">
<!ENTITY dropSchema SYSTEM "drop_schema.sgml">
+<!ENTITY dropSeqAM SYSTEM "drop_seqam.sgml">
<!ENTITY dropSequence SYSTEM "drop_sequence.sgml">
<!ENTITY dropServer SYSTEM "drop_server.sgml">
<!ENTITY dropTable SYSTEM "drop_table.sgml">
diff --git a/doc/src/sgml/ref/create_seqam.sgml b/doc/src/sgml/ref/create_seqam.sgml
new file mode 100644
index 0000000..7892820
--- /dev/null
+++ b/doc/src/sgml/ref/create_seqam.sgml
@@ -0,0 +1,174 @@
+<!--
+doc/src/sgml/ref/create_seqam.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-CREATESEQAM">
+ <indexterm zone="sql-createseqam">
+ <primary>CREATE ACCESS METHOD FOR SEQUENCES</primary>
+ </indexterm>
+
+ <refmeta>
+ <refentrytitle>CREATE ACCESS METHOD FOR SEQUENCES</refentrytitle>
+ <manvolnum>7</manvolnum>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>CREATE ACCESS METHOD FOR SEQUENCES</refname>
+ <refpurpose>define custom sequence access method</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+CREATE ACCESS METHOD FOR SEQUENCES <replaceable class="parameter">name</replaceable> (
+ EXTRACOLUMNS = <replaceable class="parameter">_function</replaceable> ,
+ RELOPTIONS = <replaceable class="parameter">reloptions_function</replaceable> ,
+ INIT = <replaceable class="parameter">init_function</replaceable> ,
+ ALLOC = <replaceable class="parameter">alloc_function</replaceable> ,
+ SETVAL = <replaceable class="parameter">setval_function</replaceable> ,
+ DUMP = <replaceable class="parameter">dump_function</replaceable>,
+ RESTORE = <replaceable class="parameter">restore_function</replaceable>
+)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>CREATE ACCESS METHOD FOR SEQUENCES</command> creates a sequence
+ access method. A sequence access method changes how values for SEQUENCEs
+ are generated.
+ </para>
+
+ <para>
+ You must be a superuser to use <command>CREATE ACCESS METHOD FOR SEQUENCES</command>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of the sequence access method to be created. This name must be
+ unique within the database.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">extracolumns_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the function that returns extra columns for the sequence
+ access method.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">reloptions_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the function for parsing reloptions for the sequence access
+ method.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">init_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the init function for the sequence access method.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">alloc_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the function which allocates new sequence id.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">setval_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the function which handles the <function>setval</function>
+ function call.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">dump_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the function used for dumping current state of the sequence
+ to a string. This function will be called by
+ <application>pg_dump</application>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">restore_function</replaceable></term>
+ <listitem>
+ <para>
+ The name of the function used for restoring the state of the sequence
+ from a string. Calls to this function will be present in a database dumps
+ created by <application>pg_dump</application>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ <para>
+ The function names can be schema-qualified if necessary. Argument types
+ are not given, since the argument list for each type of function is
+ predetermined. All functions are required.
+ </para>
+
+ <para>
+ The arguments can appear in any order, not only the one shown above.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ See the <filename>contrib/gapless_seq</> for example on how to write new
+ sequence access methods and how to use this command.
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ There is no
+ <command>CREATE ACCESS METHOD FOR SEQUENCES</command> statement in the SQL
+ standard.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-dropseqam"></member>
+ </simplelist>
+ </refsect1>
+</refentry>
diff --git a/doc/src/sgml/ref/drop_seqam.sgml b/doc/src/sgml/ref/drop_seqam.sgml
new file mode 100644
index 0000000..959b777
--- /dev/null
+++ b/doc/src/sgml/ref/drop_seqam.sgml
@@ -0,0 +1,87 @@
+<!--
+doc/src/sgml/ref/drop_seqam.sgml
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-DROPSEQAM">
+ <indexterm zone="sql-dropseqam">
+ <primary>DROP ACCESS METHOD FOR SEQUENCES</primary>
+ </indexterm>
+
+ <refmeta>
+ <refentrytitle>DROP ACCESS METHOD FOR SEQUENCES</refentrytitle>
+ <manvolnum>7</manvolnum>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>DROP ACCESS METHOD FOR SEQUENCES</refname>
+ <refpurpose>remove a custom sequence access method</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+<synopsis>
+DROP ACCESS METHOD FOR SEQUENCES [ IF EXISTS ] <replaceable class="parameter">name</replaceable>
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>DROP ACCESS METHOD FOR SEQUENCES</command> drop an existing
+ sequence access method.
+ </para>
+
+ <para>
+ You must be a superuser to use the
+ <command>DROP ACCESS METHOD FOR SEQUENCES</command>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+
+ <varlistentry>
+ <term><literal>IF EXISTS</literal></term>
+ <listitem>
+ <para>
+ Do not throw an error if the sequence access method does not exist.
+ A notice is issued in this case.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing sequence access method to be removed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ There is no
+ <command>DDROP ACCESS METHOD FOR SEQUENCES</command> statement in the SQL
+ standard.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createseqam"></member>
+ </simplelist>
+ </refsect1>
+</refentry>
diff --git a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml
index 10c9a6d..aeff87e 100644
--- a/doc/src/sgml/reference.sgml
+++ b/doc/src/sgml/reference.sgml
@@ -102,6 +102,7 @@
&createRole;
&createRule;
&createSchema;
+ &createSeqAM;
&createSequence;
&createServer;
&createTable;
@@ -144,6 +145,7 @@
&dropRole;
&dropRule;
&dropSchema;
+ &dropSeqAM;
&dropSequence;
&dropServer;
&dropTable;
diff --git a/src/backend/access/sequence/seqam.c b/src/backend/access/sequence/seqam.c
index 053da0a..ae682ab 100644
--- a/src/backend/access/sequence/seqam.c
+++ b/src/backend/access/sequence/seqam.c
@@ -68,8 +68,19 @@
#include "access/relscan.h"
#include "access/transam.h"
#include "access/xact.h"
+#include "catalog/dependency.h"
+#include "catalog/objectaccess.h"
+#include "catalog/objectaddress.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
#include "catalog/pg_seqam.h"
+#include "catalog/pg_type.h"
+#include "commands/defrem.h"
+#include "miscadmin.h"
+#include "parser/parse_func.h"
+#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
@@ -392,6 +403,324 @@ GetDefaultSeqAM(void)
return get_seqam_oid(default_seqam, false);
}
+
+/*
+ * Find seqam function by name and validate it.
+ */
+static Datum
+get_seqam_func(DefElem *defel, int attnum)
+{
+ List *funcName = defGetQualifiedName(defel);
+ Oid typeId[6];
+ Oid retTypeId;
+ int nargs;
+ Oid procOid;
+
+ typeId[0] = INTERNALOID;
+
+ switch (attnum)
+ {
+ case Anum_pg_seqam_amextracols:
+ /*
+ * This function returns internal type so it has to also accept
+ * internal on input even though there is actually no parameter
+ * sent.
+ */
+ nargs = 1;
+ retTypeId = INTERNALOID;
+ break;
+
+ case Anum_pg_seqam_amreloptions:
+ nargs = 2;
+ typeId[1] = BOOLOID;
+ retTypeId = BYTEAOID;
+ break;
+
+ case Anum_pg_seqam_aminit:
+ nargs = 5;
+ typeId[1] = INTERNALOID;
+ typeId[2] = BOOLOID;
+ typeId[3] = INTERNALOID;
+ typeId[4] = INTERNALOID;
+ retTypeId = VOIDOID;
+ break;
+
+ case Anum_pg_seqam_amalloc:
+ nargs = 4;
+ typeId[1] = INTERNALOID;
+ typeId[2] = INT8OID;
+ typeId[3] = INTERNALOID;
+ retTypeId = INT8OID;
+ break;
+
+ case Anum_pg_seqam_amsetval:
+ nargs = 3;
+ typeId[1] = INTERNALOID;
+ typeId[2] = INT8OID;
+ retTypeId = VOIDOID;
+ break;
+
+ case Anum_pg_seqam_amdump:
+ nargs = 2;
+ typeId[1] = INTERNALOID;
+ retTypeId = CSTRINGOID;
+ break;
+
+ case Anum_pg_seqam_amrestore:
+ nargs = 3;
+ typeId[1] = INTERNALOID;
+ typeId[2] = CSTRINGOID;
+ retTypeId = VOIDOID;
+ break;
+
+ default:
+ /* should not be here */
+ elog(ERROR, "unrecognized attribute for sequence access method: %d",
+ attnum);
+ nargs = 0; /* keep compiler quiet */
+ }
+
+ procOid = LookupFuncName(funcName, nargs, typeId, false);
+ if (get_func_rettype(procOid) != retTypeId)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("function %s should return type %s",
+ func_signature_string(funcName, nargs, NIL, typeId),
+ format_type_be(retTypeId))));
+
+ return ObjectIdGetDatum(procOid);
+}
+
+/*
+ * make pg_depend entries for a new pg_seqam entry
+ */
+static void
+makeSeqAMDependencies(HeapTuple tuple)
+{
+ Form_pg_seqam seqam = (Form_pg_seqam) GETSTRUCT(tuple);
+ ObjectAddress myself,
+ referenced;
+
+ myself.classId = SeqAccessMethodRelationId;
+ myself.objectId = HeapTupleGetOid(tuple);
+ myself.objectSubId = 0;
+
+ /* dependency on extension */
+ recordDependencyOnCurrentExtension(&myself, false);
+
+ /* dependencies on functions */
+ referenced.classId = ProcedureRelationId;
+ referenced.objectSubId = 0;
+
+ referenced.objectId = seqam->seqamextracols;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.objectId = seqam->seqamreloptions;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.objectId = seqam->seqaminit;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.objectId = seqam->seqamalloc;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.objectId = seqam->seqamsetval;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.objectId = seqam->seqamdump;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ referenced.objectId = seqam->seqamrestore;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+}
+
+/*
+ * Create a sequence access method record in pg_seqam catalog.
+ *
+ * Only superusers can create a sequence access methods.
+ */
+Oid
+DefineSeqAM(List *names, List *parameters)
+{
+ char *seqamname = strVal(linitial(names));
+ Oid seqamoid;
+ ListCell *pl;
+ Relation rel;
+ Datum values[Natts_pg_seqam];
+ bool nulls[Natts_pg_seqam];
+ HeapTuple tuple;
+
+ /* Must be super user. */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to create sequence access method \"%s\"",
+ seqamname),
+ errhint("Must be superuser to create a sequence access method.")));
+
+ /* Must not already exist. */
+ seqamoid = get_seqam_oid(seqamname, true);
+ if (OidIsValid(seqamoid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("sequence access method \"%s\" already exists",
+ seqamname)));
+
+ /* Initialize the values. */
+ memset(values, 0, sizeof(values));
+ memset(nulls, false, sizeof(nulls));
+
+ values[Anum_pg_seqam_amname - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(seqamname));
+
+ /*
+ * loop over the definition list and extract the information we need.
+ */
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ if (pg_strcasecmp(defel->defname, "extracolumns") == 0)
+ {
+ values[Anum_pg_seqam_amextracols - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_amextracols);
+ }
+ else if (pg_strcasecmp(defel->defname, "reloptions") == 0)
+ {
+ values[Anum_pg_seqam_amreloptions - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_amreloptions);
+ }
+ else if (pg_strcasecmp(defel->defname, "init") == 0)
+ {
+ values[Anum_pg_seqam_aminit - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_aminit);
+ }
+ else if (pg_strcasecmp(defel->defname, "alloc") == 0)
+ {
+ values[Anum_pg_seqam_amalloc - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_amalloc);
+ }
+ else if (pg_strcasecmp(defel->defname, "setval") == 0)
+ {
+ values[Anum_pg_seqam_amsetval - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_amsetval);
+ }
+ else if (pg_strcasecmp(defel->defname, "dump") == 0)
+ {
+ values[Anum_pg_seqam_amdump - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_amdump);
+ }
+ else if (pg_strcasecmp(defel->defname, "restore") == 0)
+ {
+ values[Anum_pg_seqam_amrestore - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_amrestore);
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("sequence access method parameter \"%s\" not recognized",
+ defel->defname)));
+ }
+
+ /*
+ * Validation.
+ */
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amextracols - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method extracolumns function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amreloptions - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method reloptions function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_aminit - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method init function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amalloc - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method alloc function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amsetval - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method setval function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amdump - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method dump function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_amrestore - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method restore function is required")));
+
+ /*
+ * Insert tuple into pg_seqam.
+ */
+ rel = heap_open(SeqAccessMethodRelationId, RowExclusiveLock);
+
+ tuple = heap_form_tuple(rel->rd_att, values, nulls);
+
+ seqamoid = simple_heap_insert(rel, tuple);
+
+ CatalogUpdateIndexes(rel, tuple);
+
+ makeSeqAMDependencies(tuple);
+
+ heap_freetuple(tuple);
+
+ /* Post creation hook */
+ InvokeObjectPostCreateHook(SeqAccessMethodRelationId, seqamoid, 0);
+
+ heap_close(rel, RowExclusiveLock);
+
+ return seqamoid;
+}
+
+/*
+ * Drop a sequence access method.
+ */
+void
+RemoveSeqAMById(Oid seqamoid)
+{
+ Relation rel;
+ HeapTuple tuple;
+ Form_pg_seqam seqam;
+
+ /*
+ * Find the target tuple
+ */
+ rel = heap_open(SeqAccessMethodRelationId, RowExclusiveLock);
+
+ tuple = SearchSysCache1(SEQAMOID, ObjectIdGetDatum(seqamoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for sequence access method %u",
+ seqamoid);
+
+ seqam = (Form_pg_seqam) GETSTRUCT(tuple);
+ /* Can't drop builtin local sequence access method. */
+ if (seqamoid == LOCAL_SEQAM_OID)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for sequence access method %s",
+ NameStr(seqam->seqamname))));
+
+ /*
+ * Remove the pg_seqam tuple (this will roll back if we fail below)
+ */
+ simple_heap_delete(rel, &tuple->t_self);
+
+ ReleaseSysCache(tuple);
+
+ heap_close(rel, RowExclusiveLock);
+}
+
/*
* get_seqam_oid - given a sequence AM name, look up the OID
*
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index bacb242..9340798 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -16,6 +16,7 @@
#include "access/htup_details.h"
#include "access/xact.h"
+#include "access/seqam.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
@@ -157,7 +158,8 @@ static const Oid object_classes[MAX_OCLASS] = {
DefaultAclRelationId, /* OCLASS_DEFACL */
ExtensionRelationId, /* OCLASS_EXTENSION */
EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */
- PolicyRelationId /* OCLASS_POLICY */
+ PolicyRelationId, /* OCLASS_POLICY */
+ SeqAccessMethodRelationId /* OCLASS_SEQAM */
};
@@ -1265,6 +1267,10 @@ doDeletion(const ObjectAddress *object, int flags)
RemovePolicyById(object->objectId);
break;
+ case OCLASS_SEQAM:
+ RemoveSeqAMById(object->objectId);
+ break;
+
default:
elog(ERROR, "unrecognized object class: %u",
object->classId);
@@ -2373,6 +2379,9 @@ getObjectClass(const ObjectAddress *object)
case PolicyRelationId:
return OCLASS_POLICY;
+
+ case SeqAccessMethodRelationId:
+ return OCLASS_SEQAM;
}
/* shouldn't get here */
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 2412a24..58cf813 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -430,6 +430,18 @@ static const ObjectPropertyType ObjectProperty[] =
Anum_pg_type_typacl,
ACL_KIND_TYPE,
true
+ },
+ {
+ SeqAccessMethodRelationId,
+ SeqAmOidIndexId,
+ SEQAMOID,
+ SEQAMNAME,
+ Anum_pg_seqam_amname,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
+ -1,
+ true
}
};
@@ -529,7 +541,9 @@ ObjectTypeMap[] =
/* OCLASS_EVENT_TRIGGER */
{ "event trigger", OBJECT_EVENT_TRIGGER },
/* OCLASS_POLICY */
- { "policy", OBJECT_POLICY }
+ { "policy", OBJECT_POLICY },
+ /* OCLASS_SEQAM */
+ { "sequence access method", OBJECT_SEQAM }
};
@@ -671,6 +685,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_EVENT_TRIGGER:
+ case OBJECT_SEQAM:
address = get_object_address_unqualified(objtype,
objname, missing_ok);
break;
@@ -897,6 +912,9 @@ get_object_address_unqualified(ObjectType objtype,
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger name cannot be qualified");
break;
+ case OBJECT_SEQAM:
+ msg = gettext_noop("sequence access method name cannot be qualified");
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
msg = NULL; /* placate compiler */
@@ -957,6 +975,11 @@ get_object_address_unqualified(ObjectType objtype,
address.objectId = get_event_trigger_oid(name, missing_ok);
address.objectSubId = 0;
break;
+ case OBJECT_SEQAM:
+ address.classId = SeqAccessMethodRelationId;
+ address.objectId = get_seqam_oid(name, missing_ok);
+ address.objectSubId = 0;
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
/* placate compiler, which doesn't know elog won't return */
@@ -1721,6 +1744,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
break;
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
+ case OBJECT_SEQAM:
/* We treat these object types as being owned by superusers */
if (!superuser_arg(roleid))
ereport(ERROR,
@@ -2655,6 +2679,21 @@ getObjectDescription(const ObjectAddress *object)
break;
}
+ case OCLASS_SEQAM:
+ {
+ HeapTuple tup;
+
+ tup = SearchSysCache1(SEQAMOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for sequence access method %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("sequence access method %s"),
+ NameStr(((Form_pg_seqam) GETSTRUCT(tup))->seqamname));
+ ReleaseSysCache(tup);
+ break;
+ }
+
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
@@ -3132,6 +3171,10 @@ getObjectTypeDescription(const ObjectAddress *object)
appendStringInfoString(&buffer, "policy");
break;
+ case OCLASS_SEQAM:
+ appendStringInfoString(&buffer, "sequence access method");
+ break;
+
default:
appendStringInfo(&buffer, "unrecognized %u", object->classId);
break;
@@ -4026,6 +4069,27 @@ getObjectIdentityParts(const ObjectAddress *object,
break;
}
+ case OCLASS_SEQAM:
+ {
+ char *seqamname;
+ HeapTuple tup;
+ Form_pg_seqam seqamForm;
+
+ tup = SearchSysCache1(SEQAMOID,
+ ObjectIdGetDatum(object->objectId));
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for sequence access method %u",
+ object->objectId);
+ seqamForm = (Form_pg_seqam) GETSTRUCT(tup);
+ seqamname = pstrdup(NameStr(seqamForm->seqamname));
+ ReleaseSysCache(tup);
+ appendStringInfoString(&buffer,
+ quote_identifier(seqamname));
+ if (objname)
+ *objname = list_make1(seqamname);
+ break;
+ }
+
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index e5185ba..01d772a 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -421,6 +421,10 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
args = strVal(linitial(objargs));
}
break;
+ case OBJECT_SEQAM:
+ msg = gettext_noop("sequence access method \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
default:
elog(ERROR, "unexpected object type (%d)", (int) objtype);
break;
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index a33a5ad..0c4d63e 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -72,6 +72,7 @@ typedef enum
} event_trigger_command_tag_check_result;
static event_trigger_support_data event_trigger_support[] = {
+ {"ACCESS METHOD FOR SEQUENCES", true},
{"AGGREGATE", true},
{"CAST", true},
{"CONSTRAINT", true},
@@ -1075,6 +1076,7 @@ EventTriggerSupportsObjectType(ObjectType obtype)
case OBJECT_POLICY:
case OBJECT_RULE:
case OBJECT_SCHEMA:
+ case OBJECT_SEQAM:
case OBJECT_SEQUENCE:
case OBJECT_TABCONSTRAINT:
case OBJECT_TABLE:
@@ -1134,6 +1136,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
case OCLASS_DEFACL:
case OCLASS_EXTENSION:
case OCLASS_POLICY:
+ case OCLASS_SEQAM:
return true;
case MAX_OCLASS:
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 5834b2d..fdf8465 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1530,9 +1530,26 @@ seqrel_update_relam(Oid seqoid, Oid seqamid)
if (pgcform->relam != seqamid)
{
+ ObjectAddress myself,
+ referenced;
+
pgcform->relam = seqamid;
simple_heap_update(rd, &ctup->t_self, ctup);
CatalogUpdateIndexes(rd, ctup);
+
+ /* Remove dependency on previous SeqAM */
+ deleteDependencyRecordsForClass(RelationRelationId, seqoid,
+ SeqAccessMethodRelationId,
+ DEPENDENCY_NORMAL);
+
+ /* Record dependency on new SeqAM */
+ myself.classId = RelationRelationId;
+ myself.objectId = seqoid;
+ myself.objectSubId = 0;
+ referenced.classId = SeqAccessMethodRelationId;
+ referenced.objectId = seqamid;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
heap_freetuple(ctup);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 976eb6b..fa37899 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -586,7 +586,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 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
@@ -5167,6 +5168,15 @@ DefineStmt:
n->definition = list_make1(makeDefElem("from", (Node *) $5));
$$ = (Node *)n;
}
+ | CREATE ACCESS METHOD FOR SEQUENCES name definition
+ {
+ DefineStmt *n = makeNode(DefineStmt);
+ n->kind = OBJECT_SEQAM;
+ n->args = NIL;
+ n->defnames = list_make1(makeString($6));
+ n->definition = $7;
+ $$ = (Node *)n;
+ }
;
definition: '(' def_list ')' { $$ = $2; }
@@ -5625,6 +5635,7 @@ drop_type: TABLE { $$ = OBJECT_TABLE; }
| TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; }
| TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; }
| TEXT_P SEARCH CONFIGURATION { $$ = OBJECT_TSCONFIGURATION; }
+ | ACCESS METHOD FOR SEQUENCES { $$ = OBJECT_SEQAM; }
;
any_name_list:
@@ -13356,6 +13367,7 @@ unreserved_keyword:
| MATCH
| MATERIALIZED
| MAXVALUE
+ | METHOD
| MINUTE_P
| MINVALUE
| MODE
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 3533cfa..c8e1876 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -18,6 +18,7 @@
#include "access/htup_details.h"
#include "access/reloptions.h"
+#include "access/seqam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
@@ -1106,6 +1107,11 @@ ProcessUtilitySlow(Node *parsetree,
Assert(stmt->args == NIL);
DefineCollation(stmt->defnames, stmt->definition);
break;
+ case OBJECT_SEQAM:
+ Assert(stmt->args == NIL);
+ Assert(list_length(stmt->defnames) == 1);
+ DefineSeqAM(stmt->defnames, stmt->definition);
+ break;
default:
elog(ERROR, "unrecognized define stmt type: %d",
(int) stmt->kind);
@@ -1960,6 +1966,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_POLICY:
tag = "DROP POLICY";
break;
+ case OBJECT_SEQAM:
+ tag = "DROP ACCESS METHOD FOR SEQUENCES";
+ break;
default:
tag = "???";
}
@@ -2056,6 +2065,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_COLLATION:
tag = "CREATE COLLATION";
break;
+ case OBJECT_SEQAM:
+ tag = "CREATE ACCESS METHOD FOR SEQUENCES";
+ break;
default:
tag = "???";
}
diff --git a/src/include/access/seqam.h b/src/include/access/seqam.h
index c4f6f73..b8b3b27 100644
--- a/src/include/access/seqam.h
+++ b/src/include/access/seqam.h
@@ -40,6 +40,9 @@ extern char *default_seqam;
extern Oid GetDefaultSeqAM(void);
+extern Oid DefineSeqAM(List *names, List *parameters);
+extern void RemoveSeqAMById(Oid seqamoid);
+
extern List *seqam_extra_columns(Oid seqamid);
extern void seqam_init(Oid seqamid, List *seqparams,
List *reloptions, bool is_init,
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 6481ac8..9485d02 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -148,6 +148,7 @@ typedef enum ObjectClass
OCLASS_EXTENSION, /* pg_extension */
OCLASS_EVENT_TRIGGER, /* pg_event_trigger */
OCLASS_POLICY, /* pg_policy */
+ OCLASS_SEQAM, /* pg_seqam */
MAX_OCLASS /* MUST BE LAST */
} ObjectClass;
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 0b6e148..517035f 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1817,9 +1817,9 @@ DATA(insert OID = 1576 ( setval PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 20 "
DESCR("set sequence value");
DATA(insert OID = 3078 ( pg_sequence_parameters PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2249 "26" "{26,20,20,20,20,16}" "{i,o,o,o,o,o}" "{sequence_oid,start_value,minimum_value,maximum_value,increment,cycle_option}" _null_ pg_sequence_parameters _null_ _null_ _null_));
DESCR("sequence parameters, for use by information schema");
-DATA(insert OID = 3261 ( pg_sequence_dump_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2275 "2205" _null_ _null_ _null_ _null_ pg_sequence_dump_state _null_ _null_ _null_ ));
+DATA(insert OID = 3277 ( pg_sequence_dump_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 2275 "2205" _null_ _null_ _null_ _null_ pg_sequence_dump_state _null_ _null_ _null_ ));
DESCR("Dump state of a sequence");
-DATA(insert OID = 3262 ( pg_sequence_restore_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 2278 "2205 2275" _null_ _null_ _null_ _null_ pg_sequence_restore_state _null_ _null_ _null_ ));
+DATA(insert OID = 3278 ( pg_sequence_restore_state PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 2278 "2205 2275" _null_ _null_ _null_ _null_ pg_sequence_restore_state _null_ _null_ _null_ ));
DESCR("Restore state of a sequence");
DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1562 "2275 26 23" _null_ _null_ _null_ _null_ varbit_in _null_ _null_ _null_ ));
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 2dd2f71..a9580e8 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1231,6 +1231,7 @@ typedef enum ObjectType
OBJECT_ROLE,
OBJECT_RULE,
OBJECT_SCHEMA,
+ OBJECT_SEQAM,
OBJECT_SEQUENCE,
OBJECT_TABCONSTRAINT,
OBJECT_TABLE,
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 7c243ec..ece52b0 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -236,6 +236,7 @@ PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD)
PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)
+PG_KEYWORD("method", METHOD, UNRESERVED_KEYWORD)
PG_KEYWORD("minute", MINUTE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("minvalue", MINVALUE, UNRESERVED_KEYWORD)
PG_KEYWORD("mode", MODE, UNRESERVED_KEYWORD)
--
1.9.1