From 92a30a7eb0cadb008e18053f199af7de3fc1abaa Mon Sep 17 00:00:00 2001 From: Tom Lane 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 ac559fc9b4..5f665cf3a2 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 47d6024610..1b464aae2d 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 4d81ba7dac..1c087a3903 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 e2051c5fcd..2f116d98c7 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;