From 06fad759888d5060f9b4cf4d4f4fdec777350027 Mon Sep 17 00:00:00 2001 From: Alvaro Herrera Date: Fri, 12 May 2017 17:16:26 -0300 Subject: [PATCH 1/2] fix dependencies problem --- src/backend/catalog/heap.c | 74 --------------------------------- src/backend/catalog/objectaddress.c | 20 +++++++++ src/backend/commands/statscmds.c | 18 ++++---- src/test/regress/expected/stats_ext.out | 13 ++++-- src/test/regress/sql/stats_ext.sql | 9 ++-- 5 files changed, 45 insertions(+), 89 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index ab3d83f29b..ba63939022 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1615,10 +1615,7 @@ RemoveAttributeById(Oid relid, AttrNumber attnum) heap_close(attr_rel, RowExclusiveLock); if (attnum > 0) - { RemoveStatistics(relid, attnum); - RemoveStatisticsExt(relid, attnum); - } relation_close(rel, NoLock); } @@ -1873,7 +1870,6 @@ heap_drop_with_catalog(Oid relid) * delete statistics */ RemoveStatistics(relid, 0); - RemoveStatisticsExt(relid, 0); /* * delete attribute tuples @@ -2784,76 +2780,6 @@ RemoveStatistics(Oid relid, AttrNumber attnum) heap_close(pgstatistic, RowExclusiveLock); } - -/* - * RemoveStatisticsExt --- remove entries in pg_statistic_ext for a relation - * - * If attnum is zero, remove all entries for rel; else remove only the - * one(s) involving that column. - */ -void -RemoveStatisticsExt(Oid relid, AttrNumber attnum) -{ - Relation pgstatisticext; - SysScanDesc scan; - ScanKeyData key; - HeapTuple tuple; - - /* - * Scan pg_statistic_ext to delete relevant tuples - */ - pgstatisticext = heap_open(StatisticExtRelationId, RowExclusiveLock); - - ScanKeyInit(&key, - Anum_pg_statistic_ext_stxrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(relid)); - - scan = systable_beginscan(pgstatisticext, - StatisticExtRelidIndexId, - true, NULL, 1, &key); - - while (HeapTupleIsValid(tuple = systable_getnext(scan))) - { - bool delete = false; - - if (attnum == 0) - delete = true; - else if (attnum != 0) - { - Form_pg_statistic_ext staForm; - int i; - - /* - * Decode the stxkeys array and delete any stats that involve the - * specified column. - */ - staForm = (Form_pg_statistic_ext) GETSTRUCT(tuple); - for (i = 0; i < staForm->stxkeys.dim1; i++) - { - if (staForm->stxkeys.values[i] == attnum) - { - delete = true; - break; - } - } - } - - if (delete) - { - CatalogTupleDelete(pgstatisticext, &tuple->t_self); - deleteDependencyRecordsFor(StatisticExtRelationId, - HeapTupleGetOid(tuple), - false); - } - } - - systable_endscan(scan); - - heap_close(pgstatisticext, RowExclusiveLock); -} - - /* * RelationTruncateIndexes - truncate all indexes associated * with the heap relation to zero tuples. diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index a9e529fba0..9443996dc9 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -3004,6 +3004,26 @@ getObjectDescription(const ObjectAddress *object) break; } + case OCLASS_STATISTIC_EXT: + { + HeapTuple stxTup; + Form_pg_statistic_ext stxForm; + + stxTup = SearchSysCache1(STATEXTOID, + ObjectIdGetDatum(object->objectId)); + if (!HeapTupleIsValid(stxTup)) + elog(ERROR, "could not find tuple for statistics object %u", + object->objectId); + + stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup); + + appendStringInfo(&buffer, _("statistics object %s"), + NameStr(stxForm->stxname)); + + ReleaseSysCache(stxTup); + break; + } + case OCLASS_TRANSFORM: { HeapTuple trfTup; diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c index 662b4fa15d..d3b5430369 100644 --- a/src/backend/commands/statscmds.c +++ b/src/backend/commands/statscmds.c @@ -312,24 +312,24 @@ CreateStatistics(CreateStatsStmt *stmt) relation_close(rel, NoLock); /* - * Add a dependency on the table, so that stats get dropped on DROP TABLE. - * - * XXX don't we need dependencies on the specific columns, instead? + * Add a dependency on the columns of the table, so that stats get dropped + * on DROP TABLE as well as ALTER TABLE .. DROP COLUMN. */ - ObjectAddressSet(parentobject, RelationRelationId, relid); ObjectAddressSet(childobject, StatisticExtRelationId, statoid); - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); + for (i = 0; i < numcols; i++) + { + ObjectAddressSubSet(parentobject, RelationRelationId, relid, attnums[i]); + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); + } /* * Also add dependency on the schema. This is required to ensure that we * drop the statistics on DROP SCHEMA. This is not handled automatically * by DROP TABLE because the statistics might be in a different schema - * from the table itself. (This definition is a bit bizarre for the - * single-table case, but it will make more sense if/when we support - * extended stats across multiple tables.) + * from the table itself. */ ObjectAddressSet(parentobject, NamespaceRelationId, namespaceId); - recordDependencyOn(&childobject, &parentobject, DEPENDENCY_AUTO); + recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); /* Return stats object's address */ ObjectAddressSet(address, StatisticExtRelationId, statoid); diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out index 4ccdf21a01..f2ae0ab80f 100644 --- a/src/test/regress/expected/stats_ext.out +++ b/src/test/regress/expected/stats_ext.out @@ -48,7 +48,11 @@ DROP STATISTICS regress_schema_2.ab1_a_b_stats; CREATE STATISTICS ab1_b_c_stats ON b, c FROM ab1; CREATE STATISTICS ab1_a_b_c_stats ON a, b, c FROM ab1; CREATE STATISTICS ab1_a_b_stats ON a, b FROM ab1; -ALTER TABLE ab1 DROP COLUMN a; +\set VERBOSITY terse +ALTER TABLE ab1 DROP COLUMN a; -- fail +ERROR: cannot drop table ab1 column a because other objects depend on it +ALTER TABLE ab1 DROP COLUMN a CASCADE; +NOTICE: drop cascades to 2 other objects \d ab1 Table "public.ab1" Column | Type | Collation | Nullable | Default @@ -58,7 +62,9 @@ ALTER TABLE ab1 DROP COLUMN a; Statistics: "public"."ab1_b_c_stats" (ndistinct, dependencies) ON b, c FROM ab1 -DROP TABLE ab1; +DROP TABLE ab1 CASCADE; +NOTICE: drop cascades to statistics object ab1_b_c_stats +\set VERBOSITY default -- Ensure things work sanely with SET STATISTICS 0 CREATE TABLE ab1 (a INTEGER, b INTEGER); ALTER TABLE ab1 ALTER a SET STATISTICS 0; @@ -71,7 +77,8 @@ ALTER TABLE ab1 ALTER a SET STATISTICS -1; ANALYZE ab1 (a); WARNING: extended statistics "public.ab1_a_b_stats" could not be collected for relation public.ab1 ANALYZE ab1; -DROP TABLE ab1; +DROP TABLE ab1 CASCADE; +NOTICE: drop cascades to statistics object ab1_a_b_stats -- Verify supported object types for extended statistics CREATE schema tststats; CREATE TABLE tststats.t (a int, b int, c text); diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql index 4050f33c08..df9f47a3b6 100644 --- a/src/test/regress/sql/stats_ext.sql +++ b/src/test/regress/sql/stats_ext.sql @@ -35,9 +35,12 @@ DROP STATISTICS regress_schema_2.ab1_a_b_stats; CREATE STATISTICS ab1_b_c_stats ON b, c FROM ab1; CREATE STATISTICS ab1_a_b_c_stats ON a, b, c FROM ab1; CREATE STATISTICS ab1_a_b_stats ON a, b FROM ab1; -ALTER TABLE ab1 DROP COLUMN a; +\set VERBOSITY terse +ALTER TABLE ab1 DROP COLUMN a; -- fail +ALTER TABLE ab1 DROP COLUMN a CASCADE; \d ab1 -DROP TABLE ab1; +DROP TABLE ab1 CASCADE; +\set VERBOSITY default -- Ensure things work sanely with SET STATISTICS 0 CREATE TABLE ab1 (a INTEGER, b INTEGER); @@ -49,7 +52,7 @@ ALTER TABLE ab1 ALTER a SET STATISTICS -1; -- partial analyze doesn't build stats either ANALYZE ab1 (a); ANALYZE ab1; -DROP TABLE ab1; +DROP TABLE ab1 CASCADE; -- Verify supported object types for extended statistics CREATE schema tststats; -- 2.11.0