From 9505540258c7d7d4bbafc4948af5d9945e4a9899 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 19 Jan 2024 15:00:14 +0900
Subject: [PATCH v7 3/8] Integrate addition of attributes for sequences with
 ALTER TABLE

This is a process similar to CREATE OR REPLACE VIEW, where attributes
are added to a sequence after the initial creation of its Relation.
This gives more flexibility to sequence AMs, as these may want to force
their own set of attributes to use when coupled with their computation
methods and/or underlying table AM.
---
 src/include/nodes/parsenodes.h                |  1 +
 src/backend/commands/sequence.c               | 29 +++++++++++++++++--
 src/backend/commands/tablecmds.c              | 10 +++++++
 src/backend/tcop/utility.c                    |  4 +++
 .../test_ddl_deparse/expected/alter_table.out | 10 +++++--
 .../expected/create_sequence_1.out            |  5 +++-
 .../expected/create_table.out                 | 15 ++++++++--
 .../test_ddl_deparse/test_ddl_deparse.c       |  3 ++
 8 files changed, 69 insertions(+), 8 deletions(-)

diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 124d853e49..f5fe0d2257 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2338,6 +2338,7 @@ typedef struct AlterTableStmt
 typedef enum AlterTableType
 {
 	AT_AddColumn,				/* add column */
+	AT_AddColumnToSequence,		/* implicitly via CREATE SEQUENCE */
 	AT_AddColumnToView,			/* implicitly via CREATE OR REPLACE VIEW */
 	AT_ColumnDefault,			/* alter column default */
 	AT_CookedColumnDefault,		/* add a pre-cooked column default */
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index e4c0937435..1a4fe65dbf 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -136,6 +136,9 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
 	TupleDesc	tupDesc;
 	Datum		value[SEQ_COL_LASTCOL];
 	bool		null[SEQ_COL_LASTCOL];
+	List	   *elts = NIL;
+	List	   *atcmds = NIL;
+	ListCell   *lc;
 	Datum		pgs_values[Natts_pg_sequence];
 	bool		pgs_nulls[Natts_pg_sequence];
 	int			i;
@@ -174,7 +177,6 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
 	/*
 	 * 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 = NULL;
@@ -198,7 +200,7 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
 		coldef->is_not_null = true;
 		null[i - 1] = false;
 
-		stmt->tableElts = lappend(stmt->tableElts, coldef);
+		elts = lappend(elts, coldef);
 	}
 
 	stmt->relation = seq->sequence;
@@ -208,12 +210,35 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq)
 	stmt->oncommit = ONCOMMIT_NOOP;
 	stmt->tablespacename = NULL;
 	stmt->if_not_exists = seq->if_not_exists;
+	/*
+	 * Initial relation has no attributes, these are added later.
+	 */
+	stmt->tableElts = NIL;
 
 	address = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId, NULL, NULL);
 	seqoid = address.objectId;
 	Assert(seqoid != InvalidOid);
 
 	rel = sequence_open(seqoid, AccessExclusiveLock);
+
+	/* Add all the attributes to the sequence */
+	foreach(lc, elts)
+	{
+		AlterTableCmd *atcmd;
+
+		atcmd = makeNode(AlterTableCmd);
+		atcmd->subtype = AT_AddColumnToSequence;
+		atcmd->def = (Node *) lfirst(lc);
+		atcmds = lappend(atcmds, atcmd);
+	}
+
+	/*
+	 * No recursion needed.  Note that EventTriggerAlterTableStart() should
+	 * have been called.
+	 */
+	AlterTableInternal(RelationGetRelid(rel), atcmds, false);
+	CommandCounterIncrement();
+
 	tupDesc = RelationGetDescr(rel);
 
 	/* now initialize the sequence's data */
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index dac39df83a..f6e3873b29 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4479,6 +4479,7 @@ AlterTableGetLockLevel(List *cmds)
 				 * Subcommands that may be visible to concurrent SELECTs
 				 */
 			case AT_DropColumn: /* change visible to SELECT */
+			case AT_AddColumnToSequence:	/* CREATE SEQUENCE */
 			case AT_AddColumnToView:	/* CREATE VIEW */
 			case AT_DropOids:	/* used to equiv to DropColumn */
 			case AT_EnableAlwaysRule:	/* may change SELECT rules */
@@ -4782,6 +4783,13 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
 			/* Recursion occurs during execution phase */
 			pass = AT_PASS_ADD_COL;
 			break;
+		case AT_AddColumnToSequence:	/* add column via CREATE SEQUENCE */
+			ATSimplePermissions(cmd->subtype, rel, ATT_SEQUENCE);
+			ATPrepAddColumn(wqueue, rel, recurse, recursing, false, cmd,
+							lockmode, context);
+			/* Recursion occurs during execution phase */
+			pass = AT_PASS_ADD_COL;
+			break;
 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
 			ATSimplePermissions(cmd->subtype, rel, ATT_VIEW);
 			ATPrepAddColumn(wqueue, rel, recurse, recursing, true, cmd,
@@ -5197,6 +5205,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
 	switch (cmd->subtype)
 	{
 		case AT_AddColumn:		/* ADD COLUMN */
+		case AT_AddColumnToSequence:	/* add column via CREATE SEQUENCE */
 		case AT_AddColumnToView:	/* add column via CREATE OR REPLACE VIEW */
 			address = ATExecAddColumn(wqueue, tab, rel, &cmd,
 									  cmd->recurse, false,
@@ -6358,6 +6367,7 @@ alter_table_type_to_string(AlterTableType cmdtype)
 	switch (cmdtype)
 	{
 		case AT_AddColumn:
+		case AT_AddColumnToSequence:
 		case AT_AddColumnToView:
 			return "ADD COLUMN";
 		case AT_ColumnDefault:
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b2ea8125c9..6a65db0910 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1664,7 +1664,11 @@ ProcessUtilitySlow(ParseState *pstate,
 				break;
 
 			case T_CreateSeqStmt:
+				EventTriggerAlterTableStart(parsetree);
 				address = DefineSequence(pstate, (CreateSeqStmt *) parsetree);
+				/* stashed internally */
+				commandCollected = true;
+				EventTriggerAlterTableEnd();
 				break;
 
 			case T_AlterSeqStmt:
diff --git a/src/test/modules/test_ddl_deparse/expected/alter_table.out b/src/test/modules/test_ddl_deparse/expected/alter_table.out
index 6daa186a84..24b2179455 100644
--- a/src/test/modules/test_ddl_deparse/expected/alter_table.out
+++ b/src/test/modules/test_ddl_deparse/expected/alter_table.out
@@ -25,7 +25,10 @@ NOTICE:  DDL test: type simple, tag CREATE TABLE
 CREATE TABLE grandchild () INHERITS (child);
 NOTICE:  DDL test: type simple, tag CREATE TABLE
 ALTER TABLE parent ADD COLUMN b serial;
-NOTICE:  DDL test: type simple, tag CREATE SEQUENCE
+NOTICE:  DDL test: type alter table, tag CREATE SEQUENCE
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column last_value of sequence parent_b_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column log_cnt of sequence parent_b_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column is_called of sequence parent_b_seq
 NOTICE:  DDL test: type alter table, tag ALTER TABLE
 NOTICE:    subcommand: type ADD COLUMN (and recurse) desc column b of table parent
 NOTICE:  DDL test: type simple, tag ALTER SEQUENCE
@@ -76,7 +79,10 @@ NOTICE:    subcommand: type SET NOT NULL desc column a of table parent
 NOTICE:    subcommand: type SET NOT NULL desc column a of table child
 NOTICE:    subcommand: type SET NOT NULL desc column a of table grandchild
 ALTER TABLE parent ALTER COLUMN a ADD GENERATED ALWAYS AS IDENTITY;
-NOTICE:  DDL test: type simple, tag CREATE SEQUENCE
+NOTICE:  DDL test: type alter table, tag CREATE SEQUENCE
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column last_value of sequence parent_a_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column log_cnt of sequence parent_a_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column is_called of sequence parent_a_seq
 NOTICE:  DDL test: type simple, tag ALTER SEQUENCE
 NOTICE:  DDL test: type alter table, tag ALTER TABLE
 NOTICE:    subcommand: type ADD IDENTITY (and recurse) desc column a of table parent
diff --git a/src/test/modules/test_ddl_deparse/expected/create_sequence_1.out b/src/test/modules/test_ddl_deparse/expected/create_sequence_1.out
index 5837ea484e..310ce5a6ba 100644
--- a/src/test/modules/test_ddl_deparse/expected/create_sequence_1.out
+++ b/src/test/modules/test_ddl_deparse/expected/create_sequence_1.out
@@ -8,4 +8,7 @@ CREATE SEQUENCE fkey_table_seq
   START 10
   CACHE 10
   CYCLE;
-NOTICE:  DDL test: type simple, tag CREATE SEQUENCE
+NOTICE:  DDL test: type alter table, tag CREATE SEQUENCE
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column last_value of sequence fkey_table_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column log_cnt of sequence fkey_table_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column is_called of sequence fkey_table_seq
diff --git a/src/test/modules/test_ddl_deparse/expected/create_table.out b/src/test/modules/test_ddl_deparse/expected/create_table.out
index 2178ce83e9..2be95f99f8 100644
--- a/src/test/modules/test_ddl_deparse/expected/create_table.out
+++ b/src/test/modules/test_ddl_deparse/expected/create_table.out
@@ -50,9 +50,18 @@ CREATE TABLE datatype_table (
     PRIMARY KEY (id),
     UNIQUE (id_big)
 );
-NOTICE:  DDL test: type simple, tag CREATE SEQUENCE
-NOTICE:  DDL test: type simple, tag CREATE SEQUENCE
-NOTICE:  DDL test: type simple, tag CREATE SEQUENCE
+NOTICE:  DDL test: type alter table, tag CREATE SEQUENCE
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column last_value of sequence datatype_table_id_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column log_cnt of sequence datatype_table_id_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column is_called of sequence datatype_table_id_seq
+NOTICE:  DDL test: type alter table, tag CREATE SEQUENCE
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column last_value of sequence datatype_table_id_big_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column log_cnt of sequence datatype_table_id_big_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column is_called of sequence datatype_table_id_big_seq
+NOTICE:  DDL test: type alter table, tag CREATE SEQUENCE
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column last_value of sequence datatype_table_is_small_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column log_cnt of sequence datatype_table_is_small_seq
+NOTICE:    subcommand: type ADD COLUMN TO SEQUENCE desc column is_called of sequence datatype_table_is_small_seq
 NOTICE:  DDL test: type simple, tag CREATE TABLE
 NOTICE:  DDL test: type simple, tag CREATE INDEX
 NOTICE:  DDL test: type simple, tag CREATE INDEX
diff --git a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
index 2758ae82d7..280642e81c 100644
--- a/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
+++ b/src/test/modules/test_ddl_deparse/test_ddl_deparse.c
@@ -114,6 +114,9 @@ get_altertable_subcmdinfo(PG_FUNCTION_ARGS)
 			case AT_AddColumn:
 				strtype = "ADD COLUMN";
 				break;
+			case AT_AddColumnToSequence:
+				strtype = "ADD COLUMN TO SEQUENCE";
+				break;
 			case AT_AddColumnToView:
 				strtype = "ADD COLUMN TO VIEW";
 				break;
-- 
2.45.2

