From 92a30a7eb0cadb008e18053f199af7de3fc1abaa Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Wed, 13 Apr 2016 23:33:31 -0400
Subject: [PATCH] Fix broken dependency-mongering for index operator
 classes/families.

For a long time, opclasscmds.c explained that "we do not create a
dependency link to the AM [for an opclass or opfamily], because we don't
currently support DROP ACCESS METHOD".  Commit 473b93287040b200 invented
DROP ACCESS METHOD, but it batted only 1 for 2 on adding the dependency
links, and 0 for 2 on updating the comments about the topic.

In passing, undo the same commit's entirely inappropriate decision to
blow away an existing index as a side-effect of create_am.sql.
---
 src/backend/commands/opclasscmds.c         | 21 ++++++-------
 src/test/regress/expected/create_am.out    | 35 ++++++++++------------
 src/test/regress/expected/sanity_check.out |  2 +-
 src/test/regress/sql/create_am.sql         | 21 ++++++-------
 4 files changed, 34 insertions(+), 45 deletions(-)

diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index ac559fc9b41..5f665cf3a20 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -285,14 +285,18 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
 	heap_freetuple(tup);
 
 	/*
-	 * Create dependencies for the opfamily proper.  Note: we do not create a
-	 * dependency link to the AM, because we don't currently support DROP
-	 * ACCESS METHOD.
+	 * Create dependencies for the opfamily proper.
 	 */
 	myself.classId = OperatorFamilyRelationId;
 	myself.objectId = opfamilyoid;
 	myself.objectSubId = 0;
 
+	/* dependency on access method */
+	referenced.classId = AccessMethodRelationId;
+	referenced.objectId = amoid;
+	referenced.objectSubId = 0;
+	recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
+
 	/* dependency on namespace */
 	referenced.classId = NamespaceRelationId;
 	referenced.objectId = namespaceoid;
@@ -670,20 +674,13 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	EventTriggerCollectCreateOpClass(stmt, opclassoid, operators, procedures);
 
 	/*
-	 * Create dependencies for the opclass proper.  Note: we do not create a
-	 * dependency link to the AM, because we don't currently support DROP
-	 * ACCESS METHOD.
+	 * Create dependencies for the opclass proper.  Note: we do not need a
+	 * dependency link to the AM, because that exists through the opfamily.
 	 */
 	myself.classId = OperatorClassRelationId;
 	myself.objectId = opclassoid;
 	myself.objectSubId = 0;
 
-	/* dependency on access method */
-	referenced.classId = AccessMethodRelationId;
-	referenced.objectId = amoid;
-	referenced.objectSubId = 0;
-	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
-
 	/* dependency on namespace */
 	referenced.classId = NamespaceRelationId;
 	referenced.objectId = namespaceoid;
diff --git a/src/test/regress/expected/create_am.out b/src/test/regress/expected/create_am.out
index 47d6024610d..1b464aae2dc 100644
--- a/src/test/regress/expected/create_am.out
+++ b/src/test/regress/expected/create_am.out
@@ -3,10 +3,8 @@
 --
 -- Make gist2 over gisthandler. In fact, it would be a synonym to gist.
 CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler;
--- Drop old index on fast_emp4000
-DROP INDEX grect2ind;
 -- Try to create gist2 index on fast_emp4000: fail because opclass doesn't exist
-CREATE INDEX grect2ind ON fast_emp4000 USING gist2 (home_base);
+CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base);
 ERROR:  data type box has no default operator class for access method "gist2"
 HINT:  You must specify an operator class for the index or define a default operator class for the data type.
 -- Make operator class for boxes using gist2
@@ -35,8 +33,11 @@ CREATE OPERATOR CLASS box_ops DEFAULT
 	FUNCTION 7	gist_box_same(box, box, internal),
 	FUNCTION 9	gist_box_fetch(internal);
 -- Create gist2 index on fast_emp4000
-CREATE INDEX grect2ind ON fast_emp4000 USING gist2 (home_base);
--- Now check the results from plain indexscan
+CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base);
+-- Now check the results from plain indexscan; temporarily drop existing
+-- index grect2ind to ensure it doesn't capture the plan
+BEGIN;
+DROP INDEX grect2ind;
 SET enable_seqscan = OFF;
 SET enable_indexscan = ON;
 SET enable_bitmapscan = OFF;
@@ -48,7 +49,7 @@ SELECT * FROM fast_emp4000
 ----------------------------------------------------------------
  Sort
    Sort Key: ((home_base[0])[0])
-   ->  Index Only Scan using grect2ind on fast_emp4000
+   ->  Index Only Scan using grect2ind2 on fast_emp4000
          Index Cond: (home_base @ '(2000,1000),(200,200)'::box)
 (4 rows)
 
@@ -66,7 +67,7 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
                          QUERY PLAN                          
 -------------------------------------------------------------
  Aggregate
-   ->  Index Only Scan using grect2ind on fast_emp4000
+   ->  Index Only Scan using grect2ind2 on fast_emp4000
          Index Cond: (home_base && '(1000,1000),(0,0)'::box)
 (3 rows)
 
@@ -78,10 +79,10 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
 
 EXPLAIN (COSTS OFF)
 SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
-                      QUERY PLAN                       
--------------------------------------------------------
+                       QUERY PLAN                       
+--------------------------------------------------------
  Aggregate
-   ->  Index Only Scan using grect2ind on fast_emp4000
+   ->  Index Only Scan using grect2ind2 on fast_emp4000
          Index Cond: (home_base IS NULL)
 (3 rows)
 
@@ -91,18 +92,12 @@ SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
    278
 (1 row)
 
--- Try to drop access method: fail because of depending objects
+ROLLBACK;
+-- Try to drop access method: fail because of dependent objects
 DROP ACCESS METHOD gist2;
 ERROR:  cannot drop access method gist2 because other objects depend on it
-DETAIL:  operator class box_ops for access method gist2 depends on access method gist2
-index grect2ind depends on operator class box_ops for access method gist2
+DETAIL:  index grect2ind2 depends on operator class box_ops for access method gist2
 HINT:  Use DROP ... CASCADE to drop the dependent objects too.
 -- Drop access method cascade
 DROP ACCESS METHOD gist2 CASCADE;
-NOTICE:  drop cascades to 2 other objects
-DETAIL:  drop cascades to operator class box_ops for access method gist2
-drop cascades to index grect2ind
--- Reset optimizer options
-RESET enable_seqscan;
-RESET enable_indexscan;
-RESET enable_bitmapscan;
+NOTICE:  drop cascades to index grect2ind2
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 4d81ba7dac2..1c087a39035 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -44,7 +44,7 @@ e_star|f
 emp|f
 equipment_r|f
 f_star|f
-fast_emp4000|f
+fast_emp4000|t
 float4_tbl|f
 float8_tbl|f
 func_index_heap|t
diff --git a/src/test/regress/sql/create_am.sql b/src/test/regress/sql/create_am.sql
index e2051c5fcd3..2f116d98c77 100644
--- a/src/test/regress/sql/create_am.sql
+++ b/src/test/regress/sql/create_am.sql
@@ -5,11 +5,8 @@
 -- Make gist2 over gisthandler. In fact, it would be a synonym to gist.
 CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler;
 
--- Drop old index on fast_emp4000
-DROP INDEX grect2ind;
-
 -- Try to create gist2 index on fast_emp4000: fail because opclass doesn't exist
-CREATE INDEX grect2ind ON fast_emp4000 USING gist2 (home_base);
+CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base);
 
 -- Make operator class for boxes using gist2
 CREATE OPERATOR CLASS box_ops DEFAULT
@@ -38,9 +35,12 @@ CREATE OPERATOR CLASS box_ops DEFAULT
 	FUNCTION 9	gist_box_fetch(internal);
 
 -- Create gist2 index on fast_emp4000
-CREATE INDEX grect2ind ON fast_emp4000 USING gist2 (home_base);
+CREATE INDEX grect2ind2 ON fast_emp4000 USING gist2 (home_base);
 
--- Now check the results from plain indexscan
+-- Now check the results from plain indexscan; temporarily drop existing
+-- index grect2ind to ensure it doesn't capture the plan
+BEGIN;
+DROP INDEX grect2ind;
 SET enable_seqscan = OFF;
 SET enable_indexscan = ON;
 SET enable_bitmapscan = OFF;
@@ -61,13 +61,10 @@ EXPLAIN (COSTS OFF)
 SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
 SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
 
--- Try to drop access method: fail because of depending objects
+ROLLBACK;
+
+-- Try to drop access method: fail because of dependent objects
 DROP ACCESS METHOD gist2;
 
 -- Drop access method cascade
 DROP ACCESS METHOD gist2 CASCADE;
-
--- Reset optimizer options
-RESET enable_seqscan;
-RESET enable_indexscan;
-RESET enable_bitmapscan;
-- 
GitLab