From a0a0512182cdca33d41485a5399573e6e380c229 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sat, 29 Apr 2006 16:43:54 +0000
Subject: [PATCH] Disallow changing DEFAULT expression of a SERIAL column.

Dhanaraj M
---
 src/backend/catalog/dependency.c | 88 +++++++++++++++++++++++++++++++-
 src/backend/catalog/heap.c       | 49 +++++++++++++++++-
 src/backend/commands/tablecmds.c |  7 ++-
 src/include/catalog/dependency.h |  5 +-
 src/include/catalog/heap.h       |  5 +-
 5 files changed, 149 insertions(+), 5 deletions(-)

diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 160647aed72..3e50d27e381 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.51 2006/03/16 00:31:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.52 2006/04/29 16:43:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1931,3 +1931,89 @@ getRelationDescription(StringInfo buffer, Oid relid)
 
 	ReleaseSysCache(relTup);
 }
+
+/* Recursively travel and search for the default sequence. Finally detach it */
+
+void performSequenceDefaultDeletion(const ObjectAddress *object,
+					DropBehavior behavior, int deleteFlag)
+{        
+        
+        ScanKeyData key[3];
+        int                     nkeys;
+        SysScanDesc scan;
+        HeapTuple       tup;
+        ObjectAddress otherObject;            
+	  Relation	depRel;
+	
+	  depRel = heap_open(DependRelationId, RowExclusiveLock);
+
+        ScanKeyInit(&key[0],
+                                Anum_pg_depend_classid,
+                                BTEqualStrategyNumber, F_OIDEQ,
+                                ObjectIdGetDatum(object->classId));
+        ScanKeyInit(&key[1],
+                                Anum_pg_depend_objid,
+                                BTEqualStrategyNumber, F_OIDEQ,
+                                ObjectIdGetDatum(object->objectId));
+        if (object->objectSubId != 0)
+        {
+               ScanKeyInit(&key[2],
+                                        Anum_pg_depend_objsubid,
+                                        BTEqualStrategyNumber, F_INT4EQ,
+                                        Int32GetDatum(object->objectSubId));
+                nkeys = 3;
+        }
+        else
+                nkeys = 2;
+
+        scan = systable_beginscan(depRel, DependDependerIndexId, true,
+                                                          SnapshotNow, nkeys, key);
+
+        while (HeapTupleIsValid(tup = systable_getnext(scan)))
+        {
+		
+                Form_pg_depend foundDep = (Form_pg_depend) GETSTRUCT(tup);
+
+                otherObject.classId = foundDep->refclassid;
+                otherObject.objectId = foundDep->refobjid;
+                otherObject.objectSubId = foundDep->refobjsubid;
+
+		  /* Detach the default sequence from the relation */
+		  if(deleteFlag == 1)	
+		  {	
+                	simple_heap_delete(depRel, &tup->t_self);	
+			break;
+		  }
+
+                switch (foundDep->deptype)
+                {
+                        case DEPENDENCY_NORMAL:                        
+			{
+
+				if(getObjectClass(&otherObject) == OCLASS_CLASS)
+				{
+					/* Dont allow to change the default sequence */
+					if(deleteFlag == 2)	
+					{ 
+						systable_endscan(scan);
+				                heap_close(depRel, RowExclusiveLock);
+                                        	elog(ERROR, "%s is a SERIAL sequence. Can't alter the relation", getObjectDescription(&otherObject));
+	                                        return;
+					}
+					else /* Detach the default sequence from the relation */
+					{
+						performSequenceDefaultDeletion(&otherObject, behavior, 1);
+						systable_endscan(scan);
+						heap_close(depRel, RowExclusiveLock);
+        	                                return;					
+					}
+				}
+			}
+                		
+        	}
+	}
+
+        systable_endscan(scan);
+	heap_close(depRel, RowExclusiveLock);  	
+
+}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 962a382b79d..9803720a83e 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.296 2006/04/24 01:40:48 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.297 2006/04/29 16:43:54 momjian Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -2136,3 +2136,50 @@ heap_truncate_find_FKs(List *relationIds)
 
 	return result;
 }
+
+
+/* Detach the default sequence and the relation */
+
+void 
+RemoveSequenceDefault(Oid relid, AttrNumber attnum,
+				  DropBehavior behavior, bool flag)
+{
+	Relation	attrdef_rel;
+	ScanKeyData scankeys[2];
+	SysScanDesc scan;
+	HeapTuple	tuple;
+
+	attrdef_rel = heap_open(AttrDefaultRelationId, RowExclusiveLock);
+
+	ScanKeyInit(&scankeys[0],
+				Anum_pg_attrdef_adrelid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(relid));
+	ScanKeyInit(&scankeys[1],
+				Anum_pg_attrdef_adnum,
+				BTEqualStrategyNumber, F_INT2EQ,
+				Int16GetDatum(attnum));
+
+	scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true,
+							  SnapshotNow, 2, scankeys);
+
+	/* There should be at most one matching tuple, but we loop anyway */
+	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+	{
+		ObjectAddress object;
+
+		object.classId = AttrDefaultRelationId;
+		object.objectId = HeapTupleGetOid(tuple);
+		object.objectSubId = 0;
+
+		if(flag == true) /* Detach the sequence */
+  			performSequenceDefaultDeletion(&object, behavior, 0);
+		else	/* Don't allow to change the default sequence */
+			performSequenceDefaultDeletion(&object, behavior, 2);
+
+	}
+
+	systable_endscan(scan);
+	heap_close(attrdef_rel, RowExclusiveLock);
+
+}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6483578e808..1ed5fa9bbba 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.181 2006/03/14 22:48:18 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.182 2006/04/29 16:43:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3362,6 +3362,11 @@ ATExecColumnDefault(Relation rel, const char *colName,
 	 * safety, but at present we do not expect anything to depend on the
 	 * default.
 	 */
+	if (newDefault)
+		RemoveSequenceDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false);
+	else 
+		RemoveSequenceDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true);		
+
 	RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, false);
 
 	if (newDefault)
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 8e61515b60b..4915c8dfd72 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.21 2006/03/05 15:58:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.22 2006/04/29 16:43:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -207,4 +207,7 @@ extern void shdepDropOwned(List *relids, DropBehavior behavior);
 
 extern void shdepReassignOwned(List *relids, Oid newrole);
 
+extern void performSequenceDefaultDeletion(const ObjectAddress *object,
+					DropBehavior behavior, int deleteFlag);
+
 #endif   /* DEPENDENCY_H */
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index fc50930f739..f503589f183 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.78 2006/03/05 15:58:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.79 2006/04/29 16:43:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -97,4 +97,7 @@ extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind);
 
 extern void CheckAttributeType(const char *attname, Oid atttypid);
 
+extern void RemoveSequenceDefault(Oid relid, AttrNumber attnum,
+				  DropBehavior behavior, bool flag);
+
 #endif   /* HEAP_H */
-- 
GitLab