From cfe3e1d5a483bbb2e9cdfee619a8f2da772c886a Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 1 Dec 2023 12:56:52 +0900
Subject: [PATCH v3 8/8] dummy_sequence_am: Example of sequence AM

---
 src/test/modules/Makefile                     |   1 +
 src/test/modules/dummy_sequence_am/.gitignore |   3 +
 src/test/modules/dummy_sequence_am/Makefile   |  19 +++
 .../dummy_sequence_am--1.0.sql                |  13 +++
 .../dummy_sequence_am/dummy_sequence_am.c     | 110 ++++++++++++++++++
 .../dummy_sequence_am.control                 |   5 +
 .../expected/dummy_sequence.out               |  35 ++++++
 .../modules/dummy_sequence_am/meson.build     |  33 ++++++
 .../dummy_sequence_am/sql/dummy_sequence.sql  |  17 +++
 src/test/modules/meson.build                  |   1 +
 10 files changed, 237 insertions(+)
 create mode 100644 src/test/modules/dummy_sequence_am/.gitignore
 create mode 100644 src/test/modules/dummy_sequence_am/Makefile
 create mode 100644 src/test/modules/dummy_sequence_am/dummy_sequence_am--1.0.sql
 create mode 100644 src/test/modules/dummy_sequence_am/dummy_sequence_am.c
 create mode 100644 src/test/modules/dummy_sequence_am/dummy_sequence_am.control
 create mode 100644 src/test/modules/dummy_sequence_am/expected/dummy_sequence.out
 create mode 100644 src/test/modules/dummy_sequence_am/meson.build
 create mode 100644 src/test/modules/dummy_sequence_am/sql/dummy_sequence.sql

diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 89aa41b5e3..9789235857 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -10,6 +10,7 @@ SUBDIRS = \
 		  delay_execution \
 		  dummy_index_am \
 		  dummy_seclabel \
+		  dummy_sequence_am \
 		  libpq_pipeline \
 		  plsample \
 		  spgist_name_ops \
diff --git a/src/test/modules/dummy_sequence_am/.gitignore b/src/test/modules/dummy_sequence_am/.gitignore
new file mode 100644
index 0000000000..44d119cfcc
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/.gitignore
@@ -0,0 +1,3 @@
+# Generated subdirectories
+/log/
+/results/
diff --git a/src/test/modules/dummy_sequence_am/Makefile b/src/test/modules/dummy_sequence_am/Makefile
new file mode 100644
index 0000000000..391f7ac946
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/Makefile
@@ -0,0 +1,19 @@
+# src/test/modules/dummy_sequence_am/Makefile
+
+MODULES = dummy_sequence_am
+
+EXTENSION = dummy_sequence_am
+DATA = dummy_sequence_am--1.0.sql
+
+REGRESS = dummy_sequence
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/dummy_sequence_am
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/dummy_sequence_am/dummy_sequence_am--1.0.sql b/src/test/modules/dummy_sequence_am/dummy_sequence_am--1.0.sql
new file mode 100644
index 0000000000..e12b1f9d87
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/dummy_sequence_am--1.0.sql
@@ -0,0 +1,13 @@
+/* src/test/modules/dummy_sequence_am/dummy_sequence_am--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION dummy_sequence_am" to load this file. \quit
+
+CREATE FUNCTION dummy_sequenceam_handler(internal)
+  RETURNS sequence_am_handler
+  AS 'MODULE_PATHNAME'
+  LANGUAGE C;
+
+CREATE ACCESS METHOD dummy_sequence_am
+  TYPE SEQUENCE HANDLER dummy_sequenceam_handler;
+COMMENT ON ACCESS METHOD dummy_sequence_am IS 'dummy sequence access method';
diff --git a/src/test/modules/dummy_sequence_am/dummy_sequence_am.c b/src/test/modules/dummy_sequence_am/dummy_sequence_am.c
new file mode 100644
index 0000000000..b5ee5d89da
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/dummy_sequence_am.c
@@ -0,0 +1,110 @@
+/*-------------------------------------------------------------------------
+ *
+ * dummy_sequence_am.c
+ *
+ * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *	  src/test/modules/dummy_sequence_am/dummy_sequence_am.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/sequenceam.h"
+#include "fmgr.h"
+
+PG_MODULE_MAGIC;
+
+/* this sequence is fully on-memory */
+static int	dummy_seqam_last_value = 1;
+static bool dummy_seqam_is_called = false;
+
+PG_FUNCTION_INFO_V1(dummy_sequenceam_handler);
+
+
+/* ------------------------------------------------------------------------
+ * Callbacks for the dummy sequence access method.
+ * ------------------------------------------------------------------------
+ */
+
+/*
+ * Return the table access method used by this sequence.
+ *
+ * This is just an on-memory sequence, so anything is fine.
+ */
+static const char *
+dummy_sequenceam_get_table_am(void)
+{
+	return "heap";
+}
+
+static void
+dummy_sequenceam_init(Relation rel, int64 last_value, bool is_called)
+{
+	dummy_seqam_last_value = last_value;
+	dummy_seqam_is_called = is_called;
+}
+
+static int64
+dummy_sequenceam_nextval(Relation rel, int64 incby, int64 maxv,
+						 int64 minv, int64 cache, bool cycle,
+						 int64 *last)
+{
+	dummy_seqam_last_value += incby;
+	dummy_seqam_is_called = true;
+
+	return dummy_seqam_last_value;
+}
+
+static void
+dummy_sequenceam_setval(Relation rel, int64 next, bool iscalled)
+{
+	dummy_seqam_last_value = next;
+	dummy_seqam_is_called = iscalled;
+}
+
+static void
+dummy_sequenceam_get_state(Relation rel, int64 *last_value, bool *is_called)
+{
+	*last_value = dummy_seqam_last_value;
+	*is_called = dummy_seqam_is_called;
+}
+
+static void
+dummy_sequenceam_reset(Relation rel, int64 startv, bool is_called,
+					   bool reset_state)
+{
+	dummy_seqam_last_value = startv;
+	dummy_seqam_is_called = is_called;
+}
+
+static void
+dummy_sequenceam_change_persistence(Relation rel, char newrelpersistence)
+{
+	/* nothing to do, really */
+}
+
+/* ------------------------------------------------------------------------
+ * Definition of the dummy sequence access method.
+ * ------------------------------------------------------------------------
+ */
+
+static const SequenceAmRoutine dummy_sequenceam_methods = {
+	.type = T_SequenceAmRoutine,
+	.get_table_am = dummy_sequenceam_get_table_am,
+	.init = dummy_sequenceam_init,
+	.nextval = dummy_sequenceam_nextval,
+	.setval = dummy_sequenceam_setval,
+	.get_state = dummy_sequenceam_get_state,
+	.reset = dummy_sequenceam_reset,
+	.change_persistence = dummy_sequenceam_change_persistence
+};
+
+Datum
+dummy_sequenceam_handler(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(&dummy_sequenceam_methods);
+}
diff --git a/src/test/modules/dummy_sequence_am/dummy_sequence_am.control b/src/test/modules/dummy_sequence_am/dummy_sequence_am.control
new file mode 100644
index 0000000000..9f10622f2f
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/dummy_sequence_am.control
@@ -0,0 +1,5 @@
+# dummy_sequence_am extension
+comment = 'dummy_sequence_am - sequence access method template'
+default_version = '1.0'
+module_pathname = '$libdir/dummy_sequence_am'
+relocatable = true
diff --git a/src/test/modules/dummy_sequence_am/expected/dummy_sequence.out b/src/test/modules/dummy_sequence_am/expected/dummy_sequence.out
new file mode 100644
index 0000000000..57588cea5b
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/expected/dummy_sequence.out
@@ -0,0 +1,35 @@
+CREATE EXTENSION dummy_sequence_am;
+CREATE SEQUENCE dummyseq USING dummy_sequence_am;
+SELECT nextval('dummyseq'::regclass);
+ nextval 
+---------
+       2
+(1 row)
+
+SELECT setval('dummyseq'::regclass, 14);
+ setval 
+--------
+     14
+(1 row)
+
+SELECT nextval('dummyseq'::regclass);
+ nextval 
+---------
+      15
+(1 row)
+
+-- Sequence relation exists, but it has no attributes.
+SELECT * FROM dummyseq;
+--
+(0 rows)
+
+-- Reset connection, which will reset the sequence
+\c
+SELECT nextval('dummyseq'::regclass);
+ nextval 
+---------
+       2
+(1 row)
+
+DROP SEQUENCE dummyseq;
+DROP EXTENSION dummy_sequence_am;
diff --git a/src/test/modules/dummy_sequence_am/meson.build b/src/test/modules/dummy_sequence_am/meson.build
new file mode 100644
index 0000000000..84460070e4
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/meson.build
@@ -0,0 +1,33 @@
+# Copyright (c) 2022-2023, PostgreSQL Global Development Group
+
+dummy_sequence_am_sources = files(
+  'dummy_sequence_am.c',
+)
+
+if host_system == 'windows'
+  dummy_sequence_am_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+    '--NAME', 'dummy_sequence_am',
+    '--FILEDESC', 'dummy_sequence_am - sequence access method template',])
+endif
+
+dummy_sequence_am = shared_module('dummy_sequence_am',
+  dummy_sequence_am_sources,
+  kwargs: pg_test_mod_args,
+)
+test_install_libs += dummy_sequence_am
+
+test_install_data += files(
+  'dummy_sequence_am.control',
+  'dummy_sequence_am--1.0.sql',
+)
+
+tests += {
+  'name': 'dummy_sequence_am',
+  'sd': meson.current_source_dir(),
+  'bd': meson.current_build_dir(),
+  'regress': {
+    'sql': [
+      'dummy_sequence',
+    ],
+  },
+}
diff --git a/src/test/modules/dummy_sequence_am/sql/dummy_sequence.sql b/src/test/modules/dummy_sequence_am/sql/dummy_sequence.sql
new file mode 100644
index 0000000000..c739b29a46
--- /dev/null
+++ b/src/test/modules/dummy_sequence_am/sql/dummy_sequence.sql
@@ -0,0 +1,17 @@
+CREATE EXTENSION dummy_sequence_am;
+
+CREATE SEQUENCE dummyseq USING dummy_sequence_am;
+
+SELECT nextval('dummyseq'::regclass);
+SELECT setval('dummyseq'::regclass, 14);
+SELECT nextval('dummyseq'::regclass);
+
+-- Sequence relation exists, but it has no attributes.
+SELECT * FROM dummyseq;
+
+-- Reset connection, which will reset the sequence
+\c
+SELECT nextval('dummyseq'::regclass);
+
+DROP SEQUENCE dummyseq;
+DROP EXTENSION dummy_sequence_am;
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 8fbe742d38..f5f16aaff2 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -5,6 +5,7 @@ subdir('commit_ts')
 subdir('delay_execution')
 subdir('dummy_index_am')
 subdir('dummy_seclabel')
+subdir('dummy_sequence_am')
 subdir('gin')
 subdir('injection_points')
 subdir('ldap_password_func')
-- 
2.43.0

