0002-seqam-ddl-v2.patch
text/x-diff
Patch
Format: unified
Series: patch v2-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 | 384 | 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 | 11 | 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 7286e9f2bc9f110019fbc6532fc7ff6405c385f2 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 v2
---
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 | 384 +++++++++++++++++++++++++++++++++++
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 | 11 +
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, 780 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 7896d0f..109de2a 100644
--- a/src/backend/access/sequence/seqam.c
+++ b/src/backend/access/sequence/seqam.c
@@ -68,8 +68,20 @@
#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 "parser/parse_type.h"
+#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
@@ -398,6 +410,378 @@ check_default_seqam(char **newval, void **extra, GucSource source)
/*
+ * 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_seqamreloptions:
+ nargs = 2;
+ typeId[1] = BOOLOID;
+ retTypeId = BYTEAOID;
+ break;
+
+ case Anum_pg_seqam_seqaminit:
+ nargs = 5;
+ typeId[0] = OIDOID;
+ typeId[1] = INTERNALOID;
+ typeId[2] = BYTEAOID;
+ typeId[3] = INTERNALOID;
+ typeId[4] = INTERNALOID;
+ retTypeId = VOIDOID;
+ break;
+
+ case Anum_pg_seqam_seqamalloc:
+ nargs = 4;
+ typeId[1] = INTERNALOID;
+ typeId[2] = INT8OID;
+ typeId[3] = INTERNALOID;
+ retTypeId = INT8OID;
+ break;
+
+ case Anum_pg_seqam_seqamsetval:
+ nargs = 3;
+ typeId[1] = INTERNALOID;
+ typeId[2] = INT8OID;
+ retTypeId = VOIDOID;
+ break;
+
+ case Anum_pg_seqam_seqamdump:
+ nargs = 2;
+ typeId[1] = INTERNALOID;
+ retTypeId = CSTRINGOID;
+ break;
+
+ case Anum_pg_seqam_seqamrestore:
+ 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);
+}
+
+/*
+ * Transform list of ColumnDefs into types array and names array.
+ */
+static void
+interpret_seqam_column_list(List *columns, ArrayType **seqamcoltypes,
+ ArrayType **seqamcolnames)
+{
+ int ncols = list_length(columns);
+ Datum *coltypes;
+ Datum *colnames;
+ ListCell *l;
+ int i;
+
+ if (ncols == 0)
+ {
+ *seqamcoltypes = NULL;
+ *seqamcolnames = NULL;
+ return;
+ }
+
+ coltypes = (Datum *) palloc(ncols * sizeof(Datum));
+ colnames = (Datum *) palloc(ncols * sizeof(Datum));
+
+ i = 0;
+ foreach (l, columns)
+ {
+ ColumnDef *d = (ColumnDef *) lfirst(l);
+
+ coltypes[i] = ObjectIdGetDatum(typenameTypeId(NULL, d->typeName));
+ colnames[i] = CStringGetTextDatum(d->colname);
+
+ i++;
+ }
+
+ *seqamcoltypes = construct_array(coltypes, ncols, OIDOID,
+ sizeof(Oid), true, 'i');
+ *seqamcolnames = construct_array(colnames, ncols, TEXTOID, -1, false, 'i');
+}
+
+/*
+ * make pg_depend entries for a new pg_seqam entry
+ */
+static void
+makeSeqAMDependencies(HeapTuple tuple, ArrayType *seqamcoltypes)
+{
+ Form_pg_seqam seqam = (Form_pg_seqam) GETSTRUCT(tuple);
+ int ncoltypes,
+ i;
+ Oid *coltypes;
+ ObjectAddress myself,
+ referenced;
+
+
+ myself.classId = SeqAccessMethodRelationId;
+ myself.objectId = HeapTupleGetOid(tuple);
+ myself.objectSubId = 0;
+
+ /* Dependency on extension. */
+ recordDependencyOnCurrentExtension(&myself, false);
+
+ /* Dependencies on column types.
+ *
+ * The array is always built inside this module so it should be
+ * correct.
+ */
+ ncoltypes = ARR_DIMS(seqamcoltypes)[0];
+ Assert(ARR_NDIM(seqamcoltypes) == 1 && ncoltypes > 0 &&
+ !ARR_HASNULL(seqamcoltypes) &&
+ ARR_ELEMTYPE(seqamcoltypes) == OIDOID);
+ coltypes = (Oid *) ARR_DATA_PTR(seqamcoltypes);
+
+ for (i = 0; i < ncoltypes; i++)
+ {
+ referenced.classId = TypeRelationId;
+ referenced.objectId = coltypes[i];
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+ }
+
+ /* Dependencies on functions. */
+ referenced.classId = ProcedureRelationId;
+ referenced.objectSubId = 0;
+
+ 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 *columns, List* definition)
+{
+ char *seqamname = strVal(linitial(names));
+ Oid seqamoid;
+ ListCell *pl;
+ Relation rel;
+ Datum values[Natts_pg_seqam];
+ bool nulls[Natts_pg_seqam];
+ HeapTuple tuple;
+ ArrayType *seqamcoltypes,
+ *seqamcolnames;
+
+ /* 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_seqamname - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(seqamname));
+
+ /* Get the column types and names. */
+ interpret_seqam_column_list(columns, &seqamcoltypes, &seqamcolnames);
+ if (seqamcoltypes != NULL)
+ values[Anum_pg_seqam_seqamcoltypes - 1] =
+ PointerGetDatum(seqamcoltypes);
+ else
+ nulls[Anum_pg_seqam_seqamcoltypes - 1] = true;
+ if (seqamcolnames != NULL)
+ values[Anum_pg_seqam_seqamcolnames - 1] =
+ PointerGetDatum(seqamcolnames);
+ else
+ nulls[Anum_pg_seqam_seqamcolnames - 1] = true;
+
+ /*
+ * Loop over the definition list and extract the information we need.
+ */
+ foreach(pl, definition)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ if (pg_strcasecmp(defel->defname, "reloptions") == 0)
+ {
+ values[Anum_pg_seqam_seqamreloptions - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_seqamreloptions);
+ }
+ else if (pg_strcasecmp(defel->defname, "init") == 0)
+ {
+ values[Anum_pg_seqam_seqaminit - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_seqaminit);
+ }
+ else if (pg_strcasecmp(defel->defname, "alloc") == 0)
+ {
+ values[Anum_pg_seqam_seqamalloc - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_seqamalloc);
+ }
+ else if (pg_strcasecmp(defel->defname, "setval") == 0)
+ {
+ values[Anum_pg_seqam_seqamsetval - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_seqamsetval);
+ }
+ else if (pg_strcasecmp(defel->defname, "dump") == 0)
+ {
+ values[Anum_pg_seqam_seqamdump - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_seqamdump);
+ }
+ else if (pg_strcasecmp(defel->defname, "restore") == 0)
+ {
+ values[Anum_pg_seqam_seqamrestore - 1] =
+ get_seqam_func(defel, Anum_pg_seqam_seqamrestore);
+ }
+ 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_seqamreloptions - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method reloptions function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_seqaminit - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method init function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_seqamalloc - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method alloc function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_seqamsetval - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method setval function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_seqamdump - 1])))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("sequence access method dump function is required")));
+
+ if (!OidIsValid(DatumGetObjectId(values[Anum_pg_seqam_seqamrestore - 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, seqamcoltypes);
+
+ 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
*
* If missing_ok is false, throw an error if SeqAM name not found. If true,
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..decbd12 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_seqamname,
+ 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 fc0bd83..f5f8de6 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1620,9 +1620,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 8d6a402..15e98f1 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 '(' OptTableFuncElementList ')' AS definition
+ {
+ DefineStmt *n = makeNode(DefineStmt);
+ n->kind = OBJECT_SEQAM;
+ n->defnames = list_make1(makeString($6));
+ n->args = $8;
+ n->definition = $11;
+ $$ = (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..3add752 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,10 @@ ProcessUtilitySlow(Node *parsetree,
Assert(stmt->args == NIL);
DefineCollation(stmt->defnames, stmt->definition);
break;
+ case OBJECT_SEQAM:
+ Assert(list_length(stmt->defnames) == 1);
+ DefineSeqAM(stmt->defnames, stmt->args, stmt->definition);
+ break;
default:
elog(ERROR, "unrecognized define stmt type: %d",
(int) stmt->kind);
@@ -1960,6 +1965,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 +2064,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 0a437ef..bd296c9 100644
--- a/src/include/access/seqam.h
+++ b/src/include/access/seqam.h
@@ -28,6 +28,9 @@ typedef struct SequenceHandle SequenceHandle;
extern char *default_seqam;
+extern Oid DefineSeqAM(List *names, List *columns, List *definition);
+extern void RemoveSeqAMById(Oid seqamoid);
+
extern int seqam_extra_columns(Oid seqamid, Oid **coltypes, char ***colnames);
extern void seqam_init(Oid seqamid, Oid seqrelid, List *seqparams,
List *reloptions, Datum *values, bool *nulls);
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 401250e..c11866b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -1819,9 +1819,9 @@ DATA(insert OID = 1765 ( setval PGNSP PGUID 12 1 0 0 0 f f f f t f v 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 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