Index: src/backend/commands/command.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/commands/command.c,v
retrieving revision 1.141
diff -c -r1.141 command.c
*** src/backend/commands/command.c	2001/08/21 16:36:01	1.141
--- src/backend/commands/command.c	2001/08/23 13:13:24
***************
*** 32,37 ****
--- 32,38 ----
  #include "catalog/pg_type.h"
  #include "commands/command.h"
  #include "commands/trigger.h"
+ #include "commands/defrem.h" /* For add constraint unique, primary */
  #include "executor/execdefs.h"
  #include "executor/executor.h"
  #include "miscadmin.h"
***************
*** 42,47 ****
--- 43,49 ----
  #include "parser/parse_expr.h"
  #include "parser/parse_oper.h"
  #include "parser/parse_relation.h"
+ #include "parser/analyze.h" /* For add constraint unique, primary */
  #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/fmgroids.h"
***************
*** 1339,1349 ****
  
  							break;
  						}
! 					case CONSTR_PRIMARY:
  						{
  
! 							break;
! 						}
  					default:
  						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented for that constraint type.");
  				}
--- 1341,1500 ----
  
  							break;
  						}
!                case CONSTR_UNIQUE:
  						{
+                             char  *iname = constr->name;
+                             bool  istemp = is_temp_rel_name(relationName);
+                             Relation rel;
+                             List	   *indexoidlist;
+                             List     *indexoidscan;
+                             Form_pg_attribute *rel_attrs;
+                             int num_keys = 0;
+                             int keys_matched = 0;
+                             bool index_found = false;
+                             bool index_found_unique = false;
+                             bool index_found_primary = false;
+ 
+                             /* If the constraint name is not specified, generate a name */
+                             if (iname == NULL) {
+                                Oid	indoid;
+                                int   pass = 0;
+                                char  *typename = palloc(NAMEDATALEN);
+                                Ident *key;
+ 
+                                /* Assume that the length of the attr list is already > 0 */
+ 
+                                /* Get the first attribute so we can use its name */
+                                key = (Ident *)lfirst(constr->keys);
+ 
+                                /* Initialise typename to 'key' */
+                                snprintf(typename, NAMEDATALEN, "key");
+ 
+                                for (;;)
+                                {
+                                   iname = makeObjectName(relationName, key->name, typename);
+ 
+                                   /* Check for a conflict */
+                                   indoid = RelnameFindRelid(iname);
+ 
+                                   /* If the oid was not found, then we have a safe name */
+                                   if ((!istemp && !OidIsValid(indoid)) ||
+                                      (istemp && !is_temp_rel_name(iname)))
+                                      break;
+ 
+                                   /* Found a conflict, so try a new name component */
+                                   pfree(iname);
+                                   snprintf(typename, NAMEDATALEN, "key%d", ++pass);
+                                }
+                             }
+ 
+                             /* Need to check for unique key already on field(s) */
+                             rel = heap_openr(relationName, AccessExclusiveLock);
+ 
+                             /*
+                              * First we check for limited correctness of the
+                              * constraint
+                              */
+ 
+                             rel_attrs = rel->rd_att->attrs;
+ 
+                             /* Retrieve the oids of all indices on the relation */
+                             indexoidlist = RelationGetIndexList(rel);
+                             index_found = false;
+                             index_found_unique = false;
+                             index_found_primary = false;
+ 
+                             /* Loop over all indices on the relation */
+                             foreach(indexoidscan, indexoidlist)
+                             {
+                                Oid			indexoid = lfirsti(indexoidscan);
+                                HeapTuple	indexTuple;
+                                Form_pg_index indexStruct;
+                                List	   *keyl;
+                                int         i;
+ 
+                                indexTuple = SearchSysCache(INDEXRELID,
+                                                  ObjectIdGetDatum(indexoid),
+                                                     0, 0, 0);
+ 
+                                if (!HeapTupleIsValid(indexTuple))
+                                   elog(ERROR, "ALTER TABLE/ADD CONSTRAINT: Index \"%u\" not found",
+                                      indexoid);
+                                indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
+ 
+                                /*
+                                * Make sure this index has the same number of
+                                * keys as the constraint -- It obviously won't match otherwise.
+                                */
+                                for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
+                                num_keys = length(constr->keys);
+                                keys_matched = 0;
+ 
+                                if (i == num_keys)
+                                {
+                                   /* Loop over each key in the constraint and check that there is a
+                                      corresponding key in the index. */
+                                   i = 0;
+                                   foreach(keyl, constr->keys)
+                                   {
+                                      Ident    *key = lfirst(keyl);
+ 
+                                      /* Look at key[i] in the index and check that it is over the same column
+                                         as key[i] in the constraint.  This is to differentiate between (a,b)
+                                         and (b,a) */
+                                      if (i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0)
+                                      {
+                                         int	   keyno = indexStruct->indkey[i];
+ 
+                                         if (keyno > 0)
+                                         {
+                                            char  *name = NameStr(rel_attrs[keyno - 1]->attname);
+                                            if (strcmp(name, key->name) == 0) keys_matched++;
+                                         }
+                                      }
+                                      else elog(ERROR, "ALTER TABLE/ADD CONSTRAINT: Key \"%u[%u]\" not found", indexoid, i);
+                                      i++;
+                                   }
+                                   if (keys_matched == num_keys) {
+                                      index_found = true;
+                                      index_found_unique = indexStruct->indisunique;
+                                      index_found_primary = indexStruct->indisprimary;
+                                      if (index_found_unique || index_found_primary) break;
+                                   }
+                                }
+                                ReleaseSysCache(indexTuple);
+                             }
+ 
+                             freeList(indexoidlist);
+ 
+                             if (index_found_primary)
+                                elog(ERROR, "Unique primary key already defined on relation \"%s\"", relationName);
+                             else if (index_found_unique)
+                                elog(ERROR, "Unique constraint already defined on the specified attributes in relation \"%s\"", relationName);
+ 
+                             /* If everything is ok, create the new index (constraint) */
+                             DefineIndex(
+                                relationName,
+                                iname,
+                                "btree",
+                                constr->keys,
+                                true,
+                                false,
+                                NULL,
+                                NIL);
+ 
+                             /* Issue notice */
+                             elog(NOTICE, "ALTER TABLE/ADD UNIQUE will create implicit index '%s' for table '%s'",
+                                iname, relationName);
+                             if (index_found)
+                                elog(NOTICE, "Unique constraint supercedes existing index on relation \"%s\".  Drop the existing index to remove redundancy.", relationName);
+                             pfree(iname);
  
!                             /* Finally, close relation */
!                             heap_close(rel, NoLock);
! 
!            					break;
!                          }
  					default:
  						elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented for that constraint type.");
  				}
Index: src/backend/parser/analyze.c
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/backend/parser/analyze.c,v
retrieving revision 1.196
diff -c -r1.196 analyze.c
*** src/backend/parser/analyze.c	2001/08/21 16:36:03	1.196
--- src/backend/parser/analyze.c	2001/08/23 13:14:34
***************
*** 562,568 ****
   *	from the truncated characters.	Currently it seems best to keep it simple,
   *	so that the generated names are easily predictable by a person.
   */
! static char *
  makeObjectName(char *name1, char *name2, char *typename)
  {
  	char	   *name;
--- 562,568 ----
   *	from the truncated characters.	Currently it seems best to keep it simple,
   *	so that the generated names are easily predictable by a person.
   */
! char *
  makeObjectName(char *name1, char *name2, char *typename)
  {
  	char	   *name;
Index: src/include/parser/analyze.h
===================================================================
RCS file: /home/projects/pgsql/cvsroot/pgsql/src/include/parser/analyze.h,v
retrieving revision 1.14
diff -c -r1.14 analyze.h
*** src/include/parser/analyze.h	2001/01/24 19:43:26	1.14
--- src/include/parser/analyze.h	2001/08/23 13:14:34
***************
*** 19,22 ****
--- 19,25 ----
  
  extern void CheckSelectForUpdate(Query *qry);
  
+ /* This was exported to allow ADD CONSTRAINT to make use of it */
+ extern char *makeObjectName(char *name1, char *name2, char *typename);
+ 
  #endif	 /* ANALYZE_H */
