]> granicus.if.org Git - postgresql/commitdiff
Add support for renaming domain constraints
authorPeter Eisentraut <peter_e@gmx.net>
Tue, 3 Apr 2012 05:11:51 +0000 (08:11 +0300)
committerPeter Eisentraut <peter_e@gmx.net>
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 <replaceable class="PARAMETER">name</replaceable>
     ADD <replaceable class="PARAMETER">domain_constraint</replaceable> [ NOT VALID ]
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     DROP CONSTRAINT [ IF EXISTS ] <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
+ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
+     RENAME CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> TO <replaceable class="PARAMETER">new_constraint_name</replaceable>
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     VALIDATE CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable>
 ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
@@ -102,6 +104,15 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+    <term>RENAME CONSTRAINT</term>
+    <listitem>
+     <para>
+      This form changes the name of a constraint on a domain.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry>
     <term>VALIDATE CONSTRAINT</term>
     <listitem>
@@ -182,7 +193,7 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
       <term><replaceable class="PARAMETER">constraint_name</replaceable></term>
       <listitem>
        <para>
-        Name of an existing constraint to drop.
+        Name of an existing constraint to drop or rename.
        </para>
       </listitem>
      </varlistentry>
@@ -225,6 +236,15 @@ ALTER DOMAIN <replaceable class="PARAMETER">name</replaceable>
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><replaceable class="PARAMETER">new_constraint_name</replaceable></term>
+      <listitem>
+       <para>
+        The new name for the constraint.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><replaceable class="PARAMETER">new_owner</replaceable></term>
       <listitem>
@@ -288,6 +308,13 @@ ALTER DOMAIN zipcode DROP CONSTRAINT zipchk;
 </programlisting>
   </para>
 
+  <para>
+   To rename a check constraint on a domain:
+<programlisting>
+ALTER DOMAIN zipcode RENAME CONSTRAINT zipchk TO zip_check;
+</programlisting>
+  </para>
+
   <para>
    To move the domain into a different schema:
 <programlisting>
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;