@@ -304,6 +304,7 @@ static void ATPrepAddColumn(List **wqueue, Relation rel, bool recurse, bool recu
304
304
static void ATExecAddColumn (List * * wqueue , AlteredTableInfo * tab , Relation rel ,
305
305
ColumnDef * colDef , bool isOid ,
306
306
bool recurse , bool recursing , LOCKMODE lockmode );
307
+ static void check_for_column_name_collision (Relation rel , const char * colname );
307
308
static void add_column_datatype_dependency (Oid relid , int32 attnum , Oid typid );
308
309
static void add_column_collation_dependency (Oid relid , int32 attnum , Oid collid );
309
310
static void ATPrepAddOids (List * * wqueue , Relation rel , bool recurse ,
@@ -2257,15 +2258,7 @@ renameatt_internal(Oid myrelid,
2257
2258
oldattname )));
2258
2259
2259
2260
/* 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 );
2269
2262
2270
2263
/* apply the update */
2271
2264
namestrcpy (& (attform -> attname ), newattname );
@@ -4310,17 +4303,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
4310
4303
elog (ERROR , "cache lookup failed for relation %u" , myrelid );
4311
4304
relkind = ((Form_pg_class ) GETSTRUCT (reltup ))-> relkind ;
4312
4305
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 );
4324
4308
4325
4309
/* Determine the new attribute's number */
4326
4310
if (isOid )
@@ -4562,6 +4546,46 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
4562
4546
}
4563
4547
}
4564
4548
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
+
4565
4589
/*
4566
4590
* Install a column's dependency on its datatype.
4567
4591
*/
0 commit comments