From 506c2fb7cf6e1ae2b0f627c8e30cbde9a02297ec Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Fri, 19 Jan 2024 15:00:14 +0900
Subject: [PATCH v4 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 c5f34efe27..cfe73cd737 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2353,6 +2353,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 98a28dfb45..d6f2fc3ce0 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 fbffaef196..ea63412431 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4554,6 +4554,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 */
@@ -4857,6 +4858,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,
@@ -5284,6 +5292,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,
@@ -6464,6 +6473,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 fa66b8017e..b64acfb23f 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 b5e71af9aa..7ebd85200f 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:    subcommand: type ADD CONSTRAINT (and recurse) desc constraint parent_b_not_null on table parent
@@ -71,7 +74,10 @@ ALTER TABLE parent ALTER COLUMN a SET NOT NULL;
 NOTICE:  DDL test: type alter table, tag ALTER TABLE
 NOTICE:    subcommand: type SET NOT NULL (and recurse) desc constraint parent_a_not_null on table parent
 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 75b62aff4d..69e54358ee 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 alter table, tag ALTER TABLE
 NOTICE:    subcommand: type SET ATTNOTNULL desc <NULL>
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 265ef2a547..4be07bcbc8 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.43.0

