@@ -304,6 +304,7 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu
304304static void ATExecAddColumn (List * * wqueue ,AlteredTableInfo * tab ,Relation rel ,
305305ColumnDef * colDef ,bool isOid ,
306306bool recurse ,bool recursing ,LOCKMODE lockmode );
307+ static void check_for_column_name_collision (Relation rel ,const char * colname );
307308static void add_column_datatype_dependency (Oid relid ,int32 attnum ,Oid typid );
308309static void add_column_collation_dependency (Oid relid ,int32 attnum ,Oid collid );
309310static void ATPrepAddOids (List * * wqueue ,Relation rel ,bool recurse ,
@@ -2257,15 +2258,7 @@ renameatt_internal(Oid myrelid,
22572258oldattname )));
22582259
22592260/* new name should not already exist */
2260-
2261- /* this test is deliberately not attisdropped-aware */
2262- if (SearchSysCacheExists2 (ATTNAME ,
2263- ObjectIdGetDatum (myrelid ),
2264- PointerGetDatum (newattname )))
2265- ereport (ERROR ,
2266- (errcode (ERRCODE_DUPLICATE_COLUMN ),
2267- errmsg ("column \"%s\" of relation \"%s\" already exists" ,
2268- newattname ,RelationGetRelationName (targetrelation ))));
2261+ check_for_column_name_collision (targetrelation ,newattname );
22692262
22702263/* apply the update */
22712264namestrcpy (& (attform -> attname ),newattname );
@@ -4310,17 +4303,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
43104303elog (ERROR ,"cache lookup failed for relation %u" ,myrelid );
43114304relkind = ((Form_pg_class )GETSTRUCT (reltup ))-> relkind ;
43124305
4313- /*
4314- * this test is deliberately not attisdropped-aware, since if one tries to
4315- * add a column matching a dropped column name, it's gonna fail anyway.
4316- */
4317- if (SearchSysCacheExists2 (ATTNAME ,
4318- ObjectIdGetDatum (myrelid ),
4319- PointerGetDatum (colDef -> colname )))
4320- ereport (ERROR ,
4321- (errcode (ERRCODE_DUPLICATE_COLUMN ),
4322- errmsg ("column \"%s\" of relation \"%s\" already exists" ,
4323- colDef -> colname ,RelationGetRelationName (rel ))));
4306+ /* new name should not already exist */
4307+ check_for_column_name_collision (rel ,colDef -> colname );
43244308
43254309/* Determine the new attribute's number */
43264310if (isOid )
@@ -4562,6 +4546,46 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
45624546}
45634547}
45644548
4549+ /*
4550+ * If a new or renamed column will collide with the name of an existing
4551+ * column, error out.
4552+ */
4553+ static void
4554+ check_for_column_name_collision (Relation rel ,const char * colname )
4555+ {
4556+ HeapTuple attTuple ;
4557+ int attnum ;
4558+
4559+ /*
4560+ * this test is deliberately not attisdropped-aware, since if one tries to
4561+ * add a column matching a dropped column name, it's gonna fail anyway.
4562+ */
4563+ attTuple = SearchSysCache2 (ATTNAME ,
4564+ ObjectIdGetDatum (RelationGetRelid (rel )),
4565+ PointerGetDatum (colname ));
4566+ if (!HeapTupleIsValid (attTuple ))
4567+ return ;
4568+
4569+ attnum = ((Form_pg_attribute )GETSTRUCT (attTuple ))-> attnum ;
4570+ ReleaseSysCache (attTuple );
4571+
4572+ /*
4573+ * We throw a different error message for conflicts with system column
4574+ * names, since they are normally not shown and the user might otherwise
4575+ * be confused about the reason for the conflict.
4576+ */
4577+ if (attnum <=0 )
4578+ ereport (ERROR ,
4579+ (errcode (ERRCODE_DUPLICATE_COLUMN ),
4580+ errmsg ("column name \"%s\" conflicts with a system column name" ,
4581+ colname )));
4582+ else
4583+ ereport (ERROR ,
4584+ (errcode (ERRCODE_DUPLICATE_COLUMN ),
4585+ errmsg ("column \"%s\" of relation \"%s\" already exists" ,
4586+ colname ,RelationGetRelationName (rel ))));
4587+ }
4588+
45654589/*
45664590 * Install a column's dependency on its datatype.
45674591 */