mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Apply fixes for problems with dropped columns whose types have also been
dropped. Add regression test, too.
This commit is contained in:
		@@ -8,7 +8,7 @@
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232.2.1 2002/12/16 18:39:56 tgl Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232.2.2 2003/05/12 00:17:33 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * INTERFACE ROUTINES
 | 
					 * INTERFACE ROUTINES
 | 
				
			||||||
@@ -75,7 +75,7 @@ static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin);
 | 
				
			|||||||
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
 | 
					static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
 | 
				
			||||||
static void StoreConstraints(Relation rel, TupleDesc tupdesc);
 | 
					static void StoreConstraints(Relation rel, TupleDesc tupdesc);
 | 
				
			||||||
static void SetRelationNumChecks(Relation rel, int numchecks);
 | 
					static void SetRelationNumChecks(Relation rel, int numchecks);
 | 
				
			||||||
static void RemoveStatistics(Relation rel);
 | 
					static void RemoveStatistics(Relation rel, AttrNumber attnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ----------------------------------------------------------------
 | 
					/* ----------------------------------------------------------------
 | 
				
			||||||
@@ -911,8 +911,9 @@ DeleteAttributeTuples(Oid relid)
 | 
				
			|||||||
 *		RemoveAttributeById
 | 
					 *		RemoveAttributeById
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
 | 
					 * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute
 | 
				
			||||||
 * deleted in pg_attribute.  (Everything else needed, such as getting rid
 | 
					 * deleted in pg_attribute.  We also remove pg_statistic entries for it.
 | 
				
			||||||
 * of any pg_attrdef entry, is handled by dependency.c.)
 | 
					 * (Everything else needed, such as getting rid of any pg_attrdef entry,
 | 
				
			||||||
 | 
					 * is handled by dependency.c.)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
RemoveAttributeById(Oid relid, AttrNumber attnum)
 | 
					RemoveAttributeById(Oid relid, AttrNumber attnum)
 | 
				
			||||||
@@ -946,6 +947,16 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
 | 
				
			|||||||
	/* Mark the attribute as dropped */
 | 
						/* Mark the attribute as dropped */
 | 
				
			||||||
	attStruct->attisdropped = true;
 | 
						attStruct->attisdropped = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Set the type OID to invalid.  A dropped attribute's type link cannot
 | 
				
			||||||
 | 
						 * be relied on (once the attribute is dropped, the type might be too).
 | 
				
			||||||
 | 
						 * Fortunately we do not need the type row --- the only really essential
 | 
				
			||||||
 | 
						 * information is the type's typlen and typalign, which are preserved in
 | 
				
			||||||
 | 
						 * the attribute's attlen and attalign.  We set atttypid to zero here
 | 
				
			||||||
 | 
						 * as a means of catching code that incorrectly expects it to be valid.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						attStruct->atttypid = InvalidOid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Remove any NOT NULL constraint the column may have */
 | 
						/* Remove any NOT NULL constraint the column may have */
 | 
				
			||||||
	attStruct->attnotnull = false;
 | 
						attStruct->attnotnull = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -969,6 +980,8 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	heap_close(attr_rel, RowExclusiveLock);
 | 
						heap_close(attr_rel, RowExclusiveLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						RemoveStatistics(rel, attnum);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	relation_close(rel, NoLock);
 | 
						relation_close(rel, NoLock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1143,7 +1156,7 @@ heap_drop_with_catalog(Oid rid)
 | 
				
			|||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * delete statistics
 | 
						 * delete statistics
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	RemoveStatistics(rel);
 | 
						RemoveStatistics(rel, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * delete attribute tuples
 | 
						 * delete attribute tuples
 | 
				
			||||||
@@ -1817,27 +1830,45 @@ RemoveRelConstraints(Relation rel, const char *constrName,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * RemoveStatistics --- remove entries in pg_statistic for a rel or column
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If attnum is zero, remove all entries for rel; else remove only the one
 | 
				
			||||||
 | 
					 * for that column.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
RemoveStatistics(Relation rel)
 | 
					RemoveStatistics(Relation rel, AttrNumber attnum)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Relation	pgstatistic;
 | 
						Relation	pgstatistic;
 | 
				
			||||||
	SysScanDesc scan;
 | 
						SysScanDesc scan;
 | 
				
			||||||
	ScanKeyData key;
 | 
						ScanKeyData key[2];
 | 
				
			||||||
 | 
						int			nkeys;
 | 
				
			||||||
	HeapTuple	tuple;
 | 
						HeapTuple	tuple;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pgstatistic = heap_openr(StatisticRelationName, RowExclusiveLock);
 | 
						pgstatistic = heap_openr(StatisticRelationName, RowExclusiveLock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ScanKeyEntryInitialize(&key, 0x0,
 | 
						ScanKeyEntryInitialize(&key[0], 0x0,
 | 
				
			||||||
						   Anum_pg_statistic_starelid, F_OIDEQ,
 | 
											   Anum_pg_statistic_starelid, F_OIDEQ,
 | 
				
			||||||
						   ObjectIdGetDatum(RelationGetRelid(rel)));
 | 
											   ObjectIdGetDatum(RelationGetRelid(rel)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (attnum == 0)
 | 
				
			||||||
 | 
							nkeys = 1;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							ScanKeyEntryInitialize(&key[1], 0x0,
 | 
				
			||||||
 | 
												   Anum_pg_statistic_staattnum, F_INT2EQ,
 | 
				
			||||||
 | 
												   Int16GetDatum(attnum));
 | 
				
			||||||
 | 
							nkeys = 2;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndex, true,
 | 
						scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndex, true,
 | 
				
			||||||
							  SnapshotNow, 1, &key);
 | 
												  SnapshotNow, nkeys, key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 | 
						while (HeapTupleIsValid(tuple = systable_getnext(scan)))
 | 
				
			||||||
		simple_heap_delete(pgstatistic, &tuple->t_self);
 | 
							simple_heap_delete(pgstatistic, &tuple->t_self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	systable_endscan(scan);
 | 
						systable_endscan(scan);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	heap_close(pgstatistic, RowExclusiveLock);
 | 
						heap_close(pgstatistic, RowExclusiveLock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@
 | 
				
			|||||||
 * Portions Copyright (c) 1994, Regents of the University of California
 | 
					 * Portions Copyright (c) 1994, Regents of the University of California
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * IDENTIFICATION
 | 
					 * IDENTIFICATION
 | 
				
			||||||
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57 2002/09/18 21:35:21 tgl Exp $
 | 
					 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57.2.1 2003/05/12 00:17:34 tgl Exp $
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *-------------------------------------------------------------------------
 | 
					 *-------------------------------------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -171,6 +171,15 @@ expand_targetlist(List *tlist, int command_type,
 | 
				
			|||||||
			 * the attribute, so that it gets copied to the new tuple. But
 | 
								 * the attribute, so that it gets copied to the new tuple. But
 | 
				
			||||||
			 * generate a NULL for dropped columns (we want to drop any
 | 
								 * generate a NULL for dropped columns (we want to drop any
 | 
				
			||||||
			 * old values).
 | 
								 * old values).
 | 
				
			||||||
 | 
								 *
 | 
				
			||||||
 | 
								 * When generating a NULL constant for a dropped column, we label
 | 
				
			||||||
 | 
								 * it INT4 (any other guaranteed-to-exist datatype would do as
 | 
				
			||||||
 | 
								 * well).  We can't label it with the dropped column's datatype
 | 
				
			||||||
 | 
								 * since that might not exist anymore.  It does not really
 | 
				
			||||||
 | 
								 * matter what we claim the type is, since NULL is NULL --- its
 | 
				
			||||||
 | 
								 * representation is datatype-independent.  This could perhaps
 | 
				
			||||||
 | 
								 * confuse code comparing the finished plan to the target
 | 
				
			||||||
 | 
								 * relation, however.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			Oid			atttype = att_tup->atttypid;
 | 
								Oid			atttype = att_tup->atttypid;
 | 
				
			||||||
			int32		atttypmod = att_tup->atttypmod;
 | 
								int32		atttypmod = att_tup->atttypmod;
 | 
				
			||||||
@@ -179,6 +188,8 @@ expand_targetlist(List *tlist, int command_type,
 | 
				
			|||||||
			switch (command_type)
 | 
								switch (command_type)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				case CMD_INSERT:
 | 
									case CMD_INSERT:
 | 
				
			||||||
 | 
										if (!att_tup->attisdropped)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
						new_expr = (Node *) makeConst(atttype,
 | 
											new_expr = (Node *) makeConst(atttype,
 | 
				
			||||||
													  att_tup->attlen,
 | 
																		  att_tup->attlen,
 | 
				
			||||||
													  (Datum) 0,
 | 
																		  (Datum) 0,
 | 
				
			||||||
@@ -186,27 +197,48 @@ expand_targetlist(List *tlist, int command_type,
 | 
				
			|||||||
													  att_tup->attbyval,
 | 
																		  att_tup->attbyval,
 | 
				
			||||||
													  false,	/* not a set */
 | 
																		  false,	/* not a set */
 | 
				
			||||||
													  false);
 | 
																		  false);
 | 
				
			||||||
					if (!att_tup->attisdropped)
 | 
					 | 
				
			||||||
						new_expr = coerce_type_constraints(new_expr,
 | 
											new_expr = coerce_type_constraints(new_expr,
 | 
				
			||||||
														   atttype,
 | 
																			   atttype,
 | 
				
			||||||
														   COERCE_IMPLICIT_CAST);
 | 
																			   COERCE_IMPLICIT_CAST);
 | 
				
			||||||
					break;
 | 
										}
 | 
				
			||||||
				case CMD_UPDATE:
 | 
										else
 | 
				
			||||||
					/* Insert NULLs for dropped columns */
 | 
										{
 | 
				
			||||||
					if (att_tup->attisdropped)
 | 
											/* Insert NULL for dropped column */
 | 
				
			||||||
						new_expr = (Node *) makeConst(atttype,
 | 
											new_expr = (Node *) makeConst(INT4OID,
 | 
				
			||||||
													  att_tup->attlen,
 | 
																		  sizeof(int32),
 | 
				
			||||||
													  (Datum) 0,
 | 
																		  (Datum) 0,
 | 
				
			||||||
													  true, /* isnull */
 | 
																		  true, /* isnull */
 | 
				
			||||||
													  att_tup->attbyval,
 | 
																		  true,	/* byval */
 | 
				
			||||||
													  false,	/* not a set */
 | 
																		  false,	/* not a set */
 | 
				
			||||||
													  false);
 | 
																		  false);
 | 
				
			||||||
					else
 | 
											/* label resdom with INT4, too */
 | 
				
			||||||
 | 
											atttype = INT4OID;
 | 
				
			||||||
 | 
											atttypmod = -1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									case CMD_UPDATE:
 | 
				
			||||||
 | 
										if (!att_tup->attisdropped)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
						new_expr = (Node *) makeVar(result_relation,
 | 
											new_expr = (Node *) makeVar(result_relation,
 | 
				
			||||||
													attrno,
 | 
																		attrno,
 | 
				
			||||||
													atttype,
 | 
																		atttype,
 | 
				
			||||||
													atttypmod,
 | 
																		atttypmod,
 | 
				
			||||||
													0);
 | 
																		0);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										else
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											/* Insert NULL for dropped column */
 | 
				
			||||||
 | 
											new_expr = (Node *) makeConst(INT4OID,
 | 
				
			||||||
 | 
																		  sizeof(int32),
 | 
				
			||||||
 | 
																		  (Datum) 0,
 | 
				
			||||||
 | 
																		  true, /* isnull */
 | 
				
			||||||
 | 
																		  true,	/* byval */
 | 
				
			||||||
 | 
																		  false,	/* not a set */
 | 
				
			||||||
 | 
																		  false);
 | 
				
			||||||
 | 
											/* label resdom with INT4, too */
 | 
				
			||||||
 | 
											atttype = INT4OID;
 | 
				
			||||||
 | 
											atttypmod = -1;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					elog(ERROR, "expand_targetlist: unexpected command_type");
 | 
										elog(ERROR, "expand_targetlist: unexpected command_type");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1166,3 +1166,44 @@ order by relname, attnum;
 | 
				
			|||||||
drop table p1, p2 cascade;
 | 
					drop table p1, p2 cascade;
 | 
				
			||||||
NOTICE:  Drop cascades to table c1
 | 
					NOTICE:  Drop cascades to table c1
 | 
				
			||||||
NOTICE:  Drop cascades to table gc1
 | 
					NOTICE:  Drop cascades to table gc1
 | 
				
			||||||
 | 
					-- test that operations with a dropped column do not try to reference
 | 
				
			||||||
 | 
					-- its datatype
 | 
				
			||||||
 | 
					create domain mytype as text;
 | 
				
			||||||
 | 
					create temp table foo (f1 text, f2 mytype, f3 text);
 | 
				
			||||||
 | 
					insert into foo values('aa','bb','cc');
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					 f1 | f2 | f3 
 | 
				
			||||||
 | 
					----+----+----
 | 
				
			||||||
 | 
					 aa | bb | cc
 | 
				
			||||||
 | 
					(1 row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop domain mytype cascade;
 | 
				
			||||||
 | 
					NOTICE:  Drop cascades to table foo column f2
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					 f1 | f3 
 | 
				
			||||||
 | 
					----+----
 | 
				
			||||||
 | 
					 aa | cc
 | 
				
			||||||
 | 
					(1 row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into foo values('qq','rr');
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					 f1 | f3 
 | 
				
			||||||
 | 
					----+----
 | 
				
			||||||
 | 
					 aa | cc
 | 
				
			||||||
 | 
					 qq | rr
 | 
				
			||||||
 | 
					(2 rows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					update foo set f3 = 'zz';
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					 f1 | f3 
 | 
				
			||||||
 | 
					----+----
 | 
				
			||||||
 | 
					 aa | zz
 | 
				
			||||||
 | 
					 qq | zz
 | 
				
			||||||
 | 
					(2 rows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select f3,max(f1) from foo group by f3;
 | 
				
			||||||
 | 
					 f3 | max 
 | 
				
			||||||
 | 
					----+-----
 | 
				
			||||||
 | 
					 zz | qq
 | 
				
			||||||
 | 
					(1 row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -845,3 +845,21 @@ where relname in ('p1','p2','c1','gc1') and attnum > 0 and not attisdropped
 | 
				
			|||||||
order by relname, attnum;
 | 
					order by relname, attnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
drop table p1, p2 cascade;
 | 
					drop table p1, p2 cascade;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- test that operations with a dropped column do not try to reference
 | 
				
			||||||
 | 
					-- its datatype
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create domain mytype as text;
 | 
				
			||||||
 | 
					create temp table foo (f1 text, f2 mytype, f3 text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into foo values('aa','bb','cc');
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop domain mytype cascade;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					insert into foo values('qq','rr');
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					update foo set f3 = 'zz';
 | 
				
			||||||
 | 
					select * from foo;
 | 
				
			||||||
 | 
					select f3,max(f1) from foo group by f3;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user