Make relhasrules and relhastriggers work like relhasindex, namely we let
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 10 Nov 2008 00:49:37 +0000 (00:49 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 10 Nov 2008 00:49:37 +0000 (00:49 +0000)
VACUUM reset them to false rather than trying to clean 'em up during DROP.

doc/src/sgml/catalogs.sgml
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/rewrite/rewriteRemove.c
src/backend/utils/cache/relcache.c
src/include/commands/vacuum.h

index 163c277328d09ce4aa701589aff79d50c46b48f3..dc6e82a48948d5dccae37ae70f6f5bbeca1deee6 100644 (file)
    </para>
   </note>
 
+  <note>
+   <para>
+    <literal>pg_class.relhastriggers</literal>
+    must be true if a table has any triggers in this catalog.
+   </para>
+  </note>
+
  </sect1>
 
 
index 9cfec27d5f00d192788bc67d2502198d8023a51a..8536332030cbfef1ebceb7aed42013909f34ba6b 100644 (file)
@@ -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 */
index 955e7bf4de96e41881e69c1abb2ec6a9690c8387..db645ccca80844e9f481ecd922e533a5bc1879a7 100644 (file)
@@ -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);
 
index ca0dcc131cb65904707d516c7c8908a725eac69f..f71d02b1f928257a2aca50cead567ee60369e3f8 100644 (file)
@@ -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,
index a83a0603259bcf77655509c3c95e7f082527ace5..7dcf11e699d111dc5bab25ea2c00e165f9c6fb42 100644 (file)
@@ -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);
index b75669079f9eaf56ad3c2f297e903e726be9a203..bc1c11a09f017d49dcf5fa3c50c73f71059ba8a2 100644 (file)
@@ -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
         */
index 40602c470b2b3603239fb622d2c503634ae20673..89fb84fe9e1613f08d3b919876b8848b10dc65cf 100644 (file)
@@ -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,