diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index ae9a6cfd8e..33043fda3f 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,4 +1,4 @@ - + @@ -4478,6 +4478,13 @@ + + + pg_class.relhastriggers + must be true if a table has any triggers in this catalog. + + + diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 13a66e17e9..6b95075be1 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.127 2008/11/02 01:45:27 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.128 2008/11/10 00:49:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -463,10 +463,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, */ if (!vacstmt->vacuum) { - vac_update_relstats(RelationGetRelid(onerel), + vac_update_relstats(onerel, RelationGetNumberOfBlocks(onerel), - totalrows, hasindex, - InvalidTransactionId); + totalrows, hasindex, InvalidTransactionId); for (ind = 0; ind < nindexes; ind++) { @@ -474,10 +473,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, double totalindexrows; totalindexrows = ceil(thisdata->tupleFract * totalrows); - vac_update_relstats(RelationGetRelid(Irel[ind]), + vac_update_relstats(Irel[ind], RelationGetNumberOfBlocks(Irel[ind]), - totalindexrows, false, - InvalidTransactionId); + totalindexrows, false, InvalidTransactionId); } /* report results to the stats collector, too */ diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 14ed83d1d3..aa4c18915a 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.379 2008/10/31 15:05:00 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.380 2008/11/10 00:49:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -664,6 +664,11 @@ vacuum_set_xid_limits(int freeze_min_age, bool sharedRel, * pg_class would've been obsoleted. Of course, this only works for * fixed-size never-null columns, but these are. * + * Note another assumption: that two VACUUMs/ANALYZEs on a table can't + * run in parallel, nor can VACUUM/ANALYZE run in parallel with a + * schema alteration such as adding an index, rule, or trigger. Otherwise + * our updates of relhasindex etc might overwrite uncommitted updates. + * * Another reason for doing it this way is that when we are in a lazy * VACUUM and have PROC_IN_VACUUM set, we mustn't do any updates --- * somebody vacuuming pg_class might think they could delete a tuple @@ -673,9 +678,11 @@ vacuum_set_xid_limits(int freeze_min_age, bool sharedRel, * ANALYZE. */ void -vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples, +vac_update_relstats(Relation relation, + BlockNumber num_pages, double num_tuples, bool hasindex, TransactionId frozenxid) { + Oid relid = RelationGetRelid(relation); Relation rd; HeapTuple ctup; Form_pg_class pgcform; @@ -724,6 +731,18 @@ vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples, } } + /* We also clear relhasrules and relhastriggers if needed */ + if (pgcform->relhasrules && relation->rd_rules == NULL) + { + pgcform->relhasrules = false; + dirty = true; + } + if (pgcform->relhastriggers && relation->trigdesc == NULL) + { + pgcform->relhastriggers = false; + dirty = true; + } + /* * relfrozenxid should never go backward. Caller can pass * InvalidTransactionId if it has no new data. @@ -1269,9 +1288,9 @@ full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt) FreeSpaceMapVacuum(onerel); /* update statistics in pg_class */ - vac_update_relstats(RelationGetRelid(onerel), vacrelstats->rel_pages, - vacrelstats->rel_tuples, vacrelstats->hasindex, - FreezeLimit); + vac_update_relstats(onerel, + vacrelstats->rel_pages, vacrelstats->rel_tuples, + vacrelstats->hasindex, FreezeLimit); /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, @@ -3315,7 +3334,7 @@ scan_index(Relation indrel, double num_tuples) return; /* now update statistics in pg_class */ - vac_update_relstats(RelationGetRelid(indrel), + vac_update_relstats(indrel, stats->num_pages, stats->num_index_tuples, false, InvalidTransactionId); @@ -3385,7 +3404,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel, return; /* now update statistics in pg_class */ - vac_update_relstats(RelationGetRelid(indrel), + vac_update_relstats(indrel, stats->num_pages, stats->num_index_tuples, false, InvalidTransactionId); diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 48be3f411a..246962a414 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -29,7 +29,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.109 2008/10/31 15:05:00 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.110 2008/11/10 00:49:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -186,11 +186,9 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt, FreeSpaceMapVacuum(onerel); /* Update statistics in pg_class */ - vac_update_relstats(RelationGetRelid(onerel), - vacrelstats->rel_pages, - vacrelstats->rel_tuples, - vacrelstats->hasindex, - FreezeLimit); + vac_update_relstats(onerel, + vacrelstats->rel_pages, vacrelstats->rel_tuples, + vacrelstats->hasindex, FreezeLimit); /* report results to the stats collector, too */ pgstat_report_vacuum(RelationGetRelid(onerel), onerel->rd_rel->relisshared, @@ -757,9 +755,8 @@ lazy_cleanup_index(Relation indrel, return; /* now update statistics in pg_class */ - vac_update_relstats(RelationGetRelid(indrel), - stats->num_pages, - stats->num_index_tuples, + vac_update_relstats(indrel, + stats->num_pages, stats->num_index_tuples, false, InvalidTransactionId); ereport(elevel, diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index c849296f2b..8a39e489d9 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.73 2008/06/19 00:46:05 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/rewrite/rewriteRemove.c,v 1.74 2008/11/10 00:49:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,9 +22,9 @@ #include "catalog/pg_rewrite.h" #include "miscadmin.h" #include "rewrite/rewriteRemove.h" -#include "rewrite/rewriteSupport.h" #include "utils/acl.h" #include "utils/fmgroids.h" +#include "utils/inval.h" #include "utils/lsyscache.h" #include "utils/rel.h" #include "utils/syscache.h" @@ -103,7 +103,6 @@ RemoveRewriteRuleById(Oid ruleOid) Relation event_relation; HeapTuple tuple; Oid eventRelationOid; - bool hasMoreRules; /* * Open the pg_rewrite relation. @@ -127,17 +126,13 @@ RemoveRewriteRuleById(Oid ruleOid) elog(ERROR, "could not find tuple for rule %u", ruleOid); /* - * We had better grab AccessExclusiveLock so that we know no other rule - * additions/deletions are going on for this relation. Else we cannot set - * relhasrules correctly. Besides, we don't want to be changing the - * ruleset while queries are executing on the rel. + * We had better grab AccessExclusiveLock to ensure that no queries + * are going on that might depend on this rule. (Note: a weaker lock + * would suffice if it's not an ON SELECT rule.) */ eventRelationOid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class; event_relation = heap_open(eventRelationOid, AccessExclusiveLock); - hasMoreRules = event_relation->rd_rules != NULL && - event_relation->rd_rules->numLocks > 1; - /* * Now delete the pg_rewrite tuple for the rule */ @@ -148,13 +143,10 @@ RemoveRewriteRuleById(Oid ruleOid) heap_close(RewriteRelation, RowExclusiveLock); /* - * Set pg_class 'relhasrules' field correctly for event relation. - * - * Important side effect: an SI notice is broadcast to force all backends - * (including me!) to update relcache entries with the new rule set. - * Therefore, must do this even if relhasrules is still true! + * Issue shared-inval notice to force all backends (including me!) to + * update relcache entries with the new rule set. */ - SetRelationRuleStatus(eventRelationOid, hasMoreRules, false); + CacheInvalidateRelcache(event_relation); /* Close rel, but keep lock till commit... */ heap_close(event_relation, NoLock); diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 92adfd8300..657ebf8c71 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.275 2008/11/09 21:24:32 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.276 2008/11/10 00:49:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -721,6 +721,17 @@ RelationBuildRuleLock(Relation relation) systable_endscan(rewrite_scan); heap_close(rewrite_desc, AccessShareLock); + /* + * there might not be any rules (if relhasrules is out-of-date) + */ + if (numlocks == 0) + { + relation->rd_rules = NULL; + relation->rd_rulescxt = NULL; + MemoryContextDelete(rulescxt); + return; + } + /* * form a RuleLock and insert into relation */ diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index d45c3d0c96..90446bc4f5 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.80 2008/08/13 00:07:50 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/commands/vacuum.h,v 1.81 2008/11/10 00:49:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -130,7 +130,7 @@ extern void vacuum(VacuumStmt *vacstmt, Oid relid, bool do_toast, extern void vac_open_indexes(Relation relation, LOCKMODE lockmode, int *nindexes, Relation **Irel); extern void vac_close_indexes(int nindexes, Relation *Irel, LOCKMODE lockmode); -extern void vac_update_relstats(Oid relid, +extern void vac_update_relstats(Relation relation, BlockNumber num_pages, double num_tuples, bool hasindex,