Add support for renaming domain constraints
authorPeter Eisentraut
Tue, 3 Apr 2012 05:11:51 +0000 (08:11 +0300)
committerPeter Eisentraut
Tue, 3 Apr 2012 05:11:51 +0000 (08:11 +0300)
doc/src/sgml/ref/alter_domain.sgml
src/backend/catalog/objectaddress.c
src/backend/catalog/pg_constraint.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/parser/gram.y
src/backend/parser/parse_utilcmd.c
src/include/catalog/pg_constraint.h
src/include/commands/typecmds.h
src/test/regress/expected/domain.out
src/test/regress/sql/domain.sql

index 2511a125d389d2f7e4d4876d387427064466291b..c59975af033391d6d11e3b14bd5fb1542eb9d8f8 100644 (file)
@@ -31,6 +31,8 @@ ALTER DOMAIN name
     ADD domain_constraint [ NOT VALID ]
 ALTER DOMAIN name
     DROP CONSTRAINT [ IF EXISTS ] constraint_name [ RESTRICT | CASCADE ]
+ALTER DOMAIN name
+     RENAME CONSTRAINT constraint_name TO new_constraint_name
 ALTER DOMAIN name
     VALIDATE CONSTRAINT constraint_name
 ALTER DOMAIN name
@@ -102,6 +104,15 @@ ALTER DOMAIN name
     
    
 
+   
+    RENAME CONSTRAINT
+    
+     
+      This form changes the name of a constraint on a domain.
+     
+    
+   
+
    
     VALIDATE CONSTRAINT
     
@@ -182,7 +193,7 @@ ALTER DOMAIN name
       constraint_name
       
        
-        Name of an existing constraint to drop.
+        Name of an existing constraint to drop or rename.
        
       
      
@@ -225,6 +236,15 @@ ALTER DOMAIN name
       
      
 
+     
+      new_constraint_name
+      
+       
+        The new name for the constraint.
+       
+      
+     
+
      
       new_owner
       
@@ -288,6 +308,13 @@ ALTER DOMAIN zipcode DROP CONSTRAINT zipchk;
 
   
 
+  
+   To rename a check constraint on a domain:
+
+ALTER DOMAIN zipcode RENAME CONSTRAINT zipchk TO zip_check;
+
+  
+
   
    To move the domain into a different schema:
 
index e6e0347c2bff532b444e52566d86db1cb21d47d5..250069f41078978e36df39e50bdb4646f9a77634 100644 (file)
@@ -753,7 +753,7 @@ get_object_address_relobject(ObjectType objtype, List *objname,
            case OBJECT_CONSTRAINT:
                address.classId = ConstraintRelationId;
                address.objectId =
-                   get_constraint_oid(reloid, depname, missing_ok);
+                   get_relation_constraint_oid(reloid, depname, missing_ok);
                address.objectSubId = 0;
                break;
            default:
index 342cf75270a3f4b6b19d35d4394d27ca06708055..bf174b6a46ea7abc65a794486ed5bb0ed49f6548 100644 (file)
@@ -736,12 +736,12 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 }
 
 /*
- * get_constraint_oid
+ * get_relation_constraint_oid
  *     Find a constraint on the specified relation with the specified name.
  *     Returns constraint's OID.
  */
 Oid
-get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
+get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok)
 {
    Relation    pg_constraint;
    HeapTuple   tuple;
@@ -793,6 +793,64 @@ get_constraint_oid(Oid relid, const char *conname, bool missing_ok)
    return conOid;
 }
 
+/*
+ * get_domain_constraint_oid
+ *     Find a constraint on the specified domain with the specified name.
+ *     Returns constraint's OID.
+ */
+Oid
+get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok)
+{
+   Relation    pg_constraint;
+   HeapTuple   tuple;
+   SysScanDesc scan;
+   ScanKeyData skey[1];
+   Oid         conOid = InvalidOid;
+
+   /*
+    * Fetch the constraint tuple from pg_constraint.  There may be more than
+    * one match, because constraints are not required to have unique names;
+    * if so, error out.
+    */
+   pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
+
+   ScanKeyInit(&skey[0],
+               Anum_pg_constraint_contypid,
+               BTEqualStrategyNumber, F_OIDEQ,
+               ObjectIdGetDatum(typid));
+
+   scan = systable_beginscan(pg_constraint, ConstraintTypidIndexId, true,
+                             SnapshotNow, 1, skey);
+
+   while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+   {
+       Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
+
+       if (strcmp(NameStr(con->conname), conname) == 0)
+       {
+           if (OidIsValid(conOid))
+               ereport(ERROR,
+                       (errcode(ERRCODE_DUPLICATE_OBJECT),
+                errmsg("domain \"%s\" has multiple constraints named \"%s\"",
+                       format_type_be(typid), conname)));
+           conOid = HeapTupleGetOid(tuple);
+       }
+   }
+
+   systable_endscan(scan);
+
+   /* If no such constraint exists, complain */
+   if (!OidIsValid(conOid) && !missing_ok)
+       ereport(ERROR,
+               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                errmsg("constraint \"%s\" for domain \"%s\" does not exist",
+                       conname, format_type_be(typid))));
+
+   heap_close(pg_constraint, AccessShareLock);
+
+   return conOid;
+}
+
 /*
  * Determine whether a relation can be proven functionally dependent on
  * a set of grouping columns.  If so, return TRUE and add the pg_constraint
index 9615380f05b366ff67db234e68f45fd94aafdcea..9853686fe97d9f219e75e1d8b5bda9f85928a313 100644 (file)
@@ -2333,22 +2333,32 @@ renameatt(RenameStmt *stmt)
  */
 static void
 rename_constraint_internal(Oid myrelid,
+                          Oid mytypid,
                           const char *oldconname,
                           const char *newconname,
                           bool recurse,
                           bool recursing,
                           int expected_parents)
 {
-   Relation    targetrelation;
+   Relation    targetrelation = NULL;
    Oid         constraintOid;
    HeapTuple   tuple;
    Form_pg_constraint con;
 
-   targetrelation = relation_open(myrelid, AccessExclusiveLock);
-   /* don't tell it whether we're recursing; we allow changing typed tables here */
-   renameatt_check(myrelid, RelationGetForm(targetrelation), false);
+   AssertArg(!myrelid || !mytypid);
+
+   if (mytypid)
+   {
+       constraintOid = get_domain_constraint_oid(mytypid, oldconname, false);
+   }
+   else
+   {
+       targetrelation = relation_open(myrelid, AccessExclusiveLock);
+       /* don't tell it whether we're recursing; we allow changing typed tables here */
+       renameatt_check(myrelid, RelationGetForm(targetrelation), false);
 
-   constraintOid = get_constraint_oid(myrelid, oldconname, false);
+       constraintOid = get_relation_constraint_oid(myrelid, oldconname, false);
+   }
 
    tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraintOid));
    if (!HeapTupleIsValid(tuple))
@@ -2356,7 +2366,7 @@ rename_constraint_internal(Oid myrelid,
             constraintOid);
    con = (Form_pg_constraint) GETSTRUCT(tuple);
 
-   if (con->contype == CONSTRAINT_CHECK && !con->conisonly)
+   if (myrelid && con->contype == CONSTRAINT_CHECK && !con->conisonly)
    {
        if (recurse)
        {
@@ -2376,7 +2386,7 @@ rename_constraint_internal(Oid myrelid,
                if (childrelid == myrelid)
                    continue;
 
-               rename_constraint_internal(childrelid, oldconname, newconname, false, true, numparents);
+               rename_constraint_internal(childrelid, InvalidOid, oldconname, newconname, false, true, numparents);
            }
        }
        else
@@ -2407,24 +2417,43 @@ rename_constraint_internal(Oid myrelid,
 
    ReleaseSysCache(tuple);
 
-   relation_close(targetrelation, NoLock);     /* close rel but keep lock */
+   if (targetrelation)
+       relation_close(targetrelation, NoLock);     /* close rel but keep lock */
 }
 
 void
 RenameConstraint(RenameStmt *stmt)
 {
-   Oid         relid;
+   Oid         relid = InvalidOid;
+   Oid         typid = InvalidOid;
 
-   /* lock level taken here should match rename_constraint_internal */
-   relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
-                                    false, false,
-                                    RangeVarCallbackForRenameAttribute,
-                                    NULL);
+   if (stmt->relationType == OBJECT_DOMAIN)
+   {
+       Relation    rel;
+       HeapTuple   tup;
+
+       typid = typenameTypeId(NULL,  makeTypeNameFromNameList(stmt->object));
+       rel = heap_open(TypeRelationId, RowExclusiveLock);
+       tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
+       if (!HeapTupleIsValid(tup))
+           elog(ERROR, "cache lookup failed for type %u", typid);
+       checkDomainOwner(tup);
+       ReleaseSysCache(tup);
+       heap_close(rel, NoLock);
+   }
+   else
+   {
+       /* lock level taken here should match rename_constraint_internal */
+       relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
+                                        false, false,
+                                        RangeVarCallbackForRenameAttribute,
+                                        NULL);
+   }
 
-   rename_constraint_internal(relid,
+   rename_constraint_internal(relid, typid,
                               stmt->subname,
                               stmt->newname,
-                              interpretInhOption(stmt->relation->inhOpt),      /* recursive? */
+                              stmt->relation ? interpretInhOption(stmt->relation->inhOpt) : false,     /* recursive? */
                               false,   /* recursing? */
                               0        /* expected inhcount */);
 }
index 37fe5e8dae8fab726439512bb2b1bb1e4a01eca9..701a986f43f64453fc6618096a3a9ecc9f4fbabf 100644 (file)
@@ -98,7 +98,6 @@ static Oid    findRangeCanonicalFunction(List *procname, Oid typeOid);
 static Oid findRangeSubtypeDiffFunction(List *procname, Oid subtype);
 static void validateDomainConstraint(Oid domainoid, char *ccbin);
 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
-static void checkDomainOwner(HeapTuple tup);
 static void checkEnumOwner(HeapTuple tup);
 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
                    Oid baseTypeOid,
@@ -2794,7 +2793,7 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
  * Check that the type is actually a domain and that the current user
  * has permission to do ALTER DOMAIN on it.  Throw an error if not.
  */
-static void
+void
 checkDomainOwner(HeapTuple tup)
 {
    Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
index 3827e2e1add11a0387a9dc7ca11439404e76196c..f2151ef49863e9febbd18a3c3a865d8836c60101 100644 (file)
@@ -6529,6 +6529,16 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
                    n->missing_ok = false;
                    $$ = (Node *)n;
                }
+           | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name
+               {
+                   RenameStmt *n = makeNode(RenameStmt);
+                   n->renameType = OBJECT_CONSTRAINT;
+                   n->relationType = OBJECT_DOMAIN;
+                   n->object = $3;
+                   n->subname = $6;
+                   n->newname = $8;
+                   $$ = (Node *)n;
+               }
            | ALTER FOREIGN DATA_P WRAPPER name RENAME TO name
                {
                    RenameStmt *n = makeNode(RenameStmt);
index 43f5634d16c693cb8afd8bfcb9d14ea525b0be09..7c315f6c8718d71edbe1b1665cb20e9e0b4be7f1 100644 (file)
@@ -802,7 +802,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
 
            /* Copy comment on constraint */
            if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
-               (comment = GetComment(get_constraint_oid(RelationGetRelid(relation),
+               (comment = GetComment(get_relation_constraint_oid(RelationGetRelid(relation),
                                                         n->conname, false),
                                      ConstraintRelationId,
                                      0)) != NULL)
index 77015ae2f36e81a5327b2861b6a3638cba9a9d77..22d65951bd8baf43227bad15ad20dd0e82d3e125 100644 (file)
@@ -244,7 +244,8 @@ extern char *ChooseConstraintName(const char *name1, const char *name2,
 
 extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
                          Oid newNspId, bool isType);
-extern Oid get_constraint_oid(Oid relid, const char *conname, bool missing_ok);
+extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok);
+extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok);
 
 extern bool check_functional_grouping(Oid relid,
                          Index varno, Index varlevelsup,
index 0c7e10d392d372d91498176df6517bfd20abe51c..bb4a7c32bc2b4d5693c6f8db1ca2ed8ecfc87689 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef TYPECMDS_H
 #define TYPECMDS_H
 
+#include "access/htup.h"
 #include "nodes/parsenodes.h"
 
 
@@ -35,6 +36,8 @@ extern void AlterDomainValidateConstraint(List *names, char *constrName);
 extern void AlterDomainDropConstraint(List *names, const char *constrName,
                                      DropBehavior behavior, bool missing_ok);
 
+extern void checkDomainOwner(HeapTuple tup);
+
 extern List *GetDomainConstraints(Oid typeOid);
 
 extern void RenameType(RenameStmt *stmt);
index e713b97056979d907f47c350a22fd7cf8ee40055..03204ff79f703c7ef22dfd83817e5fefef751cd8 100644 (file)
@@ -659,3 +659,10 @@ create domain testdomain1 as int;
 alter domain testdomain1 rename to testdomain2;
 alter type testdomain2 rename to testdomain3;  -- alter type also works
 drop domain testdomain3;
+--
+-- Renaming domain constraints
+--
+create domain testdomain1 as int constraint unsigned check (value > 0);
+alter domain testdomain1 rename constraint unsigned to unsigned_foo;
+alter domain testdomain1 drop constraint unsigned_foo;
+drop domain testdomain1;
index ad049b7ba54360caef81a5cb92d4bd14ccb9939d..5af36af1ef136ed50688143f83479223eb39bc99 100644 (file)
@@ -496,3 +496,13 @@ create domain testdomain1 as int;
 alter domain testdomain1 rename to testdomain2;
 alter type testdomain2 rename to testdomain3;  -- alter type also works
 drop domain testdomain3;
+
+
+--
+-- Renaming domain constraints
+--
+
+create domain testdomain1 as int constraint unsigned check (value > 0);
+alter domain testdomain1 rename constraint unsigned to unsigned_foo;
+alter domain testdomain1 drop constraint unsigned_foo;
+drop domain testdomain1;