]> granicus.if.org Git - postgresql/commitdiff
Fix dependencies generated during ALTER TABLE ADD CONSTRAINT USING INDEX.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 11 Aug 2012 16:51:24 +0000 (12:51 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 11 Aug 2012 16:51:24 +0000 (12:51 -0400)
This command generated new pg_depend entries linking the index to the
constraint and the constraint to the table, which match the entries made
when a unique or primary key constraint is built de novo.  However, it did
not bother to get rid of the entries linking the index directly to the
table.  We had considered the issue when the ADD CONSTRAINT USING INDEX
patch was written, and concluded that we didn't need to get rid of the
extra entries.  But this is wrong: ALTER COLUMN TYPE wasn't expecting such
redundant dependencies to exist, as reported by Hubert Depesz Lubaczewski.
On reflection it seems rather likely to break other things as well, since
there are many bits of code that crawl pg_depend for one purpose or
another, and most of them are pretty naive about what relationships they're
expecting to find.  Fortunately it's not that hard to get rid of the extra
dependency entries, so let's do that.

Back-patch to 9.1, where ALTER TABLE ADD CONSTRAINT USING INDEX was added.

src/backend/catalog/index.c
src/backend/commands/tablecmds.c
src/include/catalog/index.h

index 1546d480e372f13b33d4f1ee8754aa157d74e1e9..464950b9af3e2f3a4b41ad85c652541146f87ab2 100644 (file)
@@ -923,6 +923,7 @@ index_create(Relation heapRelation,
                                                                        initdeferred,
                                                                        false,          /* already marked primary */
                                                                        false,          /* pg_index entry is OK */
+                                                                       false,          /* no old dependencies */
                                                                        allow_system_table_mods);
                }
                else
@@ -1090,6 +1091,8 @@ index_create(Relation heapRelation,
  * initdeferred: constraint is INITIALLY DEFERRED
  * mark_as_primary: if true, set flags to mark index as primary key
  * update_pgindex: if true, update pg_index row (else caller's done that)
+ * remove_old_dependencies: if true, remove existing dependencies of index
+ *             on table's columns
  * allow_system_table_mods: allow table to be a system catalog
  */
 void
@@ -1102,6 +1105,7 @@ index_constraint_create(Relation heapRelation,
                                                bool initdeferred,
                                                bool mark_as_primary,
                                                bool update_pgindex,
+                                               bool remove_old_dependencies,
                                                bool allow_system_table_mods)
 {
        Oid                     namespaceId = RelationGetNamespace(heapRelation);
@@ -1125,6 +1129,19 @@ index_constraint_create(Relation heapRelation,
                constraintType != CONSTRAINT_EXCLUSION)
                elog(ERROR, "constraints cannot have index expressions");
 
+       /*
+        * If we're manufacturing a constraint for a pre-existing index, we need
+        * to get rid of the existing auto dependencies for the index (the ones
+        * that index_create() would have made instead of calling this function).
+        *
+        * Note: this code would not necessarily do the right thing if the index
+        * has any expressions or predicate, but we'd never be turning such an
+        * index into a UNIQUE or PRIMARY KEY constraint.
+        */
+       if (remove_old_dependencies)
+               deleteDependencyRecordsForClass(RelationRelationId, indexRelationId,
+                                                                               RelationRelationId, DEPENDENCY_AUTO);
+
        /*
         * Construct a pg_constraint entry.
         */
@@ -1159,12 +1176,8 @@ index_constraint_create(Relation heapRelation,
        /*
         * Register the index as internally dependent on the constraint.
         *
-        * Note that the constraint has a dependency on the table, so when this
-        * path is taken we do not need any direct dependency from the index to
-        * the table.  (But if one exists, no great harm is done, either.  So in
-        * the case where we're manufacturing a constraint for a pre-existing
-        * index, we don't bother to try to get rid of the existing index->table
-        * dependency.)
+        * Note that the constraint has a dependency on the table, so we don't
+        * need (or want) any direct dependency from the index to the table.
         */
        myself.classId = RelationRelationId;
        myself.objectId = indexRelationId;
index a69544853fa1b55f648cc110cc079ffc98e962fa..00fe1138b2e5f6e0158eee3128355bdb14ace868 100644 (file)
@@ -5487,7 +5487,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
                                                        stmt->deferrable,
                                                        stmt->initdeferred,
                                                        stmt->primary,
-                                                       true,
+                                                       true, /* update pg_index */
+                                                       true, /* remove old dependencies */
                                                        allowSystemTableMods);
 
        index_close(indexRel, NoLock);
index 7c8198f31ee1519cc087192c5fa57d28196298d5..eb417cecb7493b0386e9d47ae114242a2334e97f 100644 (file)
@@ -61,6 +61,7 @@ extern void index_constraint_create(Relation heapRelation,
                                                bool initdeferred,
                                                bool mark_as_primary,
                                                bool update_pgindex,
+                                               bool remove_old_dependencies,
                                                bool allow_system_table_mods);
 
 extern void index_drop(Oid indexId, bool concurrent);