Replace pg_class.reltriggers with relhastriggers, which is just a boolean hint
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 Nov 2008 21:24:33 +0000 (21:24 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 9 Nov 2008 21:24:33 +0000 (21:24 +0000)
("there might be triggers") rather than an exact count.  This is necessary
catalog infrastructure for the upcoming patch to reduce the strength of
locking needed for trigger addition/removal.  Split out and committed
separately for ease of reviewing/testing.

In passing, also get rid of the unused pg_class columns relukeys, relfkeys,
and relrefs, which haven't been maintained in many years and now have no
chance of ever being maintained (because of wishing to avoid locking).

Simon Riggs

13 files changed:
doc/src/sgml/catalogs.sgml
src/backend/catalog/heap.c
src/backend/catalog/system_views.sql
src/backend/commands/trigger.c
src/backend/rewrite/rewriteDefine.c
src/backend/utils/cache/relcache.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/psql/describe.c
src/include/catalog/catversion.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_class.h
src/test/regress/expected/rules.out

index 66f74f4a4e6751e5cfecc7ec0c635c452dcb2a1f..163c277328d09ce4aa701589aff79d50c46b48f3 100644 (file)
       </entry>
      </row>
 
-     <row>
-      <entry><structfield>reltriggers</structfield></entry>
-      <entry><type>int2</type></entry>
-      <entry></entry>
-      <entry>
-       Number of triggers on the table; see
-       <link linkend="catalog-pg-trigger"><structname>pg_trigger</structname></link> catalog
-      </entry>
-     </row>
-
-     <row>
-      <entry><structfield>relukeys</structfield></entry>
-      <entry><type>int2</type></entry>
-      <entry></entry>
-      <entry>Unused  (<emphasis>not</emphasis> the number of unique keys)</entry>
-     </row>
-
-     <row>
-      <entry><structfield>relfkeys</structfield></entry>
-      <entry><type>int2</type></entry>
-      <entry></entry>
-      <entry>Unused  (<emphasis>not</emphasis> the number of foreign keys on the table)</entry>
-     </row>
-
-     <row>
-      <entry><structfield>relrefs</structfield></entry>
-      <entry><type>int2</type></entry>
-      <entry></entry>
-      <entry>Unused</entry>
-     </row>
-
      <row>
       <entry><structfield>relhasoids</structfield></entry>
       <entry><type>bool</type></entry>
       <entry><type>bool</type></entry>
       <entry></entry>
       <entry>
-       True if table has rules; see
+       True if table has (or once had) rules; see
        <link linkend="catalog-pg-rewrite"><structname>pg_rewrite</structname></link> catalog
       </entry>
      </row>
 
+     <row>
+      <entry><structfield>relhastriggers</structfield></entry>
+      <entry><type>bool</type></entry>
+      <entry></entry>
+      <entry>
+       True if table has (or once had) triggers; see
+       <link linkend="catalog-pg-trigger"><structname>pg_trigger</structname></link> catalog
+      </entry>
+     </row>
+
      <row>
       <entry><structfield>relhassubclass</structfield></entry>
       <entry><type>bool</type></entry>
    </para>
   </note>
 
-  <note>
-   <para>
-    <literal>pg_class.reltriggers</literal> needs to agree with the
-    number of triggers found in this table for each relation.
-   </para>
-  </note>
-
  </sect1>
 
 
       <entry><structfield>hasrules</structfield></entry>
       <entry><type>boolean</type></entry>
       <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relhasrules</literal></entry>
-      <entry>true if table has rules</entry>
+      <entry>true if table has (or once had) rules</entry>
      </row>
      <row>
       <entry><structfield>hastriggers</structfield></entry>
       <entry><type>boolean</type></entry>
-      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.reltriggers</literal></entry>
-      <entry>true if table has triggers</entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relhastriggers</literal></entry>
+      <entry>true if table has (or once had) triggers</entry>
      </row>
     </tbody>
    </tgroup>
index b79db1fd837f0884cc4f80624fb50d234beca562..eb67b0c43d3f8a3386adb14c5a91497fbd030e5d 100644 (file)
@@ -641,13 +641,10 @@ InsertPgClassTuple(Relation pg_class_desc,
        values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
        values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
        values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
-       values[Anum_pg_class_reltriggers - 1] = Int16GetDatum(rd_rel->reltriggers);
-       values[Anum_pg_class_relukeys - 1] = Int16GetDatum(rd_rel->relukeys);
-       values[Anum_pg_class_relfkeys - 1] = Int16GetDatum(rd_rel->relfkeys);
-       values[Anum_pg_class_relrefs - 1] = Int16GetDatum(rd_rel->relrefs);
        values[Anum_pg_class_relhasoids - 1] = BoolGetDatum(rd_rel->relhasoids);
        values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey);
        values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules);
+       values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
        values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
        values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
        /* start out with empty permissions */
@@ -2366,7 +2363,7 @@ heap_truncate_check_FKs(List *relations, bool tempTables)
        {
                Relation        rel = lfirst(cell);
 
-               if (rel->rd_rel->reltriggers != 0)
+               if (rel->rd_rel->relhastriggers)
                        oids = lappend_oid(oids, RelationGetRelid(rel));
        }
 
index 45e559396cc1bd54a06c560355cd6306ad79935d..cd953343a981e52d5f7e2d6e91a2d1901ce09e36 100644 (file)
@@ -84,7 +84,7 @@ CREATE VIEW pg_tables AS
         T.spcname AS tablespace,
         C.relhasindex AS hasindexes, 
         C.relhasrules AS hasrules, 
-        (C.reltriggers > 0) AS hastriggers 
+        C.relhastriggers AS hastriggers 
     FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) 
          LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace)
     WHERE C.relkind = 'r';
index f6872c552baa491e56ecfd76d49a667eeb1a6a1f..dd20f3795a9a977f52c0d901eac9dec00403e328 100644 (file)
@@ -95,7 +95,6 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
        Oid                     funcoid;
        Oid                     funcrettype;
        Oid                     trigoid;
-       int                     found = 0;
        int                     i;
        char            constrtrigname[NAMEDATALEN];
        char       *trigname;
@@ -280,10 +279,9 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
        }
 
        /*
-        * Scan pg_trigger for existing triggers on relation.  We do this mainly
-        * because we must count them; a secondary benefit is to give a nice error
-        * message if there's already a trigger of the same name. (The unique
-        * index on tgrelid/tgname would complain anyway.)
+        * Scan pg_trigger for existing triggers on relation.  We do this only
+        * to give a nice error message if there's already a trigger of the same
+        * name.  (The unique index on tgrelid/tgname would complain anyway.)
         *
         * NOTE that this is cool only because we have AccessExclusiveLock on the
         * relation, so the trigger set won't be changing underneath us.
@@ -303,7 +301,6 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
                                        (errcode(ERRCODE_DUPLICATE_OBJECT),
                                  errmsg("trigger \"%s\" for relation \"%s\" already exists",
                                                 trigname, stmt->relation->relname)));
-               found++;
        }
        systable_endscan(tgscan);
 
@@ -405,7 +402,7 @@ CreateTrigger(CreateTrigStmt *stmt, Oid constraintOid)
                elog(ERROR, "cache lookup failed for relation %u",
                         RelationGetRelid(rel));
 
-       ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
+       ((Form_pg_class) GETSTRUCT(tuple))->relhastriggers = true;
 
        simple_heap_update(pgrel, &tuple->t_self, tuple);
 
@@ -818,9 +815,6 @@ RemoveTriggerById(Oid trigOid)
        HeapTuple       tup;
        Oid                     relid;
        Relation        rel;
-       Relation        pgrel;
-       HeapTuple       tuple;
-       Form_pg_class classForm;
 
        tgrel = heap_open(TriggerRelationId, RowExclusiveLock);
 
@@ -867,33 +861,15 @@ RemoveTriggerById(Oid trigOid)
        heap_close(tgrel, RowExclusiveLock);
 
        /*
-        * Update relation's pg_class entry.  Crucial side-effect: other backends
-        * (and this one too!) are sent SI message to make them rebuild relcache
-        * entries.
-        *
-        * Note this is OK only because we have AccessExclusiveLock on the rel, so
-        * no one else is creating/deleting triggers on this rel at the same time.
+        * We do not bother to try to determine whether any other triggers remain,
+        * which would be needed in order to decide whether it's safe to clear
+        * the relation's relhastriggers.  (In any case, there might be a
+        * concurrent process adding new triggers.)  Instead, just force a
+        * relcache inval to make other backends (and this one too!) rebuild
+        * their relcache entries.  There's no great harm in leaving relhastriggers
+        * true even if there are no triggers left.
         */
-       pgrel = heap_open(RelationRelationId, RowExclusiveLock);
-       tuple = SearchSysCacheCopy(RELOID,
-                                                          ObjectIdGetDatum(relid),
-                                                          0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "cache lookup failed for relation %u", relid);
-       classForm = (Form_pg_class) GETSTRUCT(tuple);
-
-       if (classForm->reltriggers == 0)        /* should not happen */
-               elog(ERROR, "relation \"%s\" has reltriggers = 0",
-                        RelationGetRelationName(rel));
-       classForm->reltriggers--;
-
-       simple_heap_update(pgrel, &tuple->t_self, tuple);
-
-       CatalogUpdateIndexes(pgrel, tuple);
-
-       heap_freetuple(tuple);
-
-       heap_close(pgrel, RowExclusiveLock);
+       CacheInvalidateRelcache(rel);
 
        /* Keep lock on trigger's rel until end of xact */
        heap_close(rel, NoLock);
@@ -1134,18 +1110,23 @@ void
 RelationBuildTriggers(Relation relation)
 {
        TriggerDesc *trigdesc;
-       int                     ntrigs = relation->rd_rel->reltriggers;
+       int                     numtrigs;
+       int                     maxtrigs;
        Trigger    *triggers;
-       int                     found = 0;
        Relation        tgrel;
        ScanKeyData skey;
        SysScanDesc tgscan;
        HeapTuple       htup;
        MemoryContext oldContext;
+       int                     i;
 
-       Assert(ntrigs > 0);                     /* else I should not have been called */
-
-       triggers = (Trigger *) palloc(ntrigs * sizeof(Trigger));
+       /*
+        * Allocate a working array to hold the triggers (the array is extended
+        * if necessary)
+        */
+       maxtrigs = 16;
+       triggers = (Trigger *) palloc(maxtrigs * sizeof(Trigger));
+       numtrigs = 0;
 
        /*
         * Note: since we scan the triggers using TriggerRelidNameIndexId, we will
@@ -1167,10 +1148,12 @@ RelationBuildTriggers(Relation relation)
                Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(htup);
                Trigger    *build;
 
-               if (found >= ntrigs)
-                       elog(ERROR, "too many trigger records found for relation \"%s\"",
-                                RelationGetRelationName(relation));
-               build = &(triggers[found]);
+               if (numtrigs >= maxtrigs)
+               {
+                       maxtrigs *= 2;
+                       triggers = (Trigger *) repalloc(triggers, maxtrigs * sizeof(Trigger));
+               }
+               build = &(triggers[numtrigs]);
 
                build->tgoid = HeapTupleGetOid(htup);
                build->tgname = DatumGetCString(DirectFunctionCall1(nameout,
@@ -1199,7 +1182,6 @@ RelationBuildTriggers(Relation relation)
                        bytea      *val;
                        bool            isnull;
                        char       *p;
-                       int                     i;
 
                        val = DatumGetByteaP(fastgetattr(htup,
                                                                                         Anum_pg_trigger_tgargs,
@@ -1218,23 +1200,25 @@ RelationBuildTriggers(Relation relation)
                else
                        build->tgargs = NULL;
 
-               found++;
+               numtrigs++;
        }
 
        systable_endscan(tgscan);
        heap_close(tgrel, AccessShareLock);
 
-       if (found != ntrigs)
-               elog(ERROR, "%d trigger record(s) not found for relation \"%s\"",
-                        ntrigs - found,
-                        RelationGetRelationName(relation));
+       /* There might not be any triggers */
+       if (numtrigs == 0)
+       {
+               pfree(triggers);
+               return;
+       }
 
        /* Build trigdesc */
        trigdesc = (TriggerDesc *) palloc0(sizeof(TriggerDesc));
        trigdesc->triggers = triggers;
-       trigdesc->numtriggers = ntrigs;
-       for (found = 0; found < ntrigs; found++)
-               InsertTrigger(trigdesc, &(triggers[found]), found);
+       trigdesc->numtriggers = numtrigs;
+       for (i = 0; i < numtrigs; i++)
+               InsertTrigger(trigdesc, &(triggers[i]), i);
 
        /* Copy completed trigdesc into cache storage */
        oldContext = MemoryContextSwitchTo(CacheMemoryContext);
index 70e5c047144d2d78f463f23a9b68678ad85e7e0d..10cd5abccfa484cf8fb8b02ad13875e9cbba887d 100644 (file)
@@ -371,7 +371,11 @@ DefineQueryRewrite(char *rulename,
                 *
                 * If so, check that the relation is empty because the storage for the
                 * relation is going to be deleted.  Also insist that the rel not have
-                * any triggers, indexes, or child tables.
+                * any triggers, indexes, or child tables.  (Note: these tests are
+                * too strict, because they will reject relations that once had such
+                * but don't anymore.  But we don't really care, because this whole
+                * business of converting relations to views is just a kluge to allow
+                * loading ancient pg_dump files.)
                 */
                if (event_relation->rd_rel->relkind != RELKIND_VIEW)
                {
@@ -385,7 +389,7 @@ DefineQueryRewrite(char *rulename,
                                                                RelationGetRelationName(event_relation))));
                        heap_endscan(scanDesc);
 
-                       if (event_relation->rd_rel->reltriggers != 0)
+                       if (event_relation->rd_rel->relhastriggers)
                                ereport(ERROR,
                                                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                                 errmsg("could not convert table \"%s\" to a view because it has triggers",
index e614f2fcf246152455c689f70c07c93d6a20e8d3..b75669079f9eaf56ad3c2f297e903e726be9a203 100644 (file)
@@ -856,7 +856,7 @@ RelationBuildDesc(Oid targetRelId, Relation oldrelation)
                relation->rd_rulescxt = NULL;
        }
 
-       if (relation->rd_rel->reltriggers > 0)
+       if (relation->rd_rel->relhastriggers)
                RelationBuildTriggers(relation);
        else
                relation->trigdesc = NULL;
@@ -2641,7 +2641,7 @@ RelationCacheInitializePhase2(void)
                 */
                if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
                        RelationBuildRuleLock(relation);
-               if (relation->rd_rel->reltriggers > 0 && relation->trigdesc == NULL)
+               if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
                        RelationBuildTriggers(relation);
        }
 
index cd1268f32ddb3bdd722368e10db8ae10a6132f8b..b686c2834036d77f733beed0ac4a860ddcd9f1e1 100644 (file)
@@ -3070,7 +3070,7 @@ getTables(int *numTables)
        int                     i_relacl;
        int                     i_rolname;
        int                     i_relchecks;
-       int                     i_reltriggers;
+       int                     i_relhastriggers;
        int                     i_relhasindex;
        int                     i_relhasrules;
        int                     i_relhasoids;
@@ -3102,7 +3102,7 @@ getTables(int *numTables)
         * we cannot correctly identify inherited columns, owned sequences, etc.
         */
 
-       if (g_fout->remoteVersion >= 80200)
+       if (g_fout->remoteVersion >= 80400)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
@@ -3112,7 +3112,36 @@ getTables(int *numTables)
                                                  "SELECT c.tableoid, c.oid, relname, "
                                                  "relacl, relkind, relnamespace, "
                                                  "(%s relowner) as rolname, "
-                                                 "relchecks, reltriggers, "
+                                                 "relchecks, relhastriggers, "
+                                                 "relhasindex, relhasrules, relhasoids, "
+                                                 "d.refobjid as owning_tab, "
+                                                 "d.refobjsubid as owning_col, "
+                                                 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
+                                                 "array_to_string(c.reloptions, ', ') as reloptions "
+                                                 "from pg_class c "
+                                                 "left join pg_depend d on "
+                                                 "(c.relkind = '%c' and "
+                                                 "d.classid = c.tableoid and d.objid = c.oid and "
+                                                 "d.objsubid = 0 and "
+                                                 "d.refclassid = c.tableoid and d.deptype = 'a') "
+                                                 "where relkind in ('%c', '%c', '%c', '%c') "
+                                                 "order by c.oid",
+                                                 username_subquery,
+                                                 RELKIND_SEQUENCE,
+                                                 RELKIND_RELATION, RELKIND_SEQUENCE,
+                                                 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
+       }
+       else if (g_fout->remoteVersion >= 80200)
+       {
+               /*
+                * Left join to pick up dependency info linking sequences to their
+                * owning column, if any (note this dependency is AUTO as of 8.2)
+                */
+               appendPQExpBuffer(query,
+                                                 "SELECT c.tableoid, c.oid, relname, "
+                                                 "relacl, relkind, relnamespace, "
+                                                 "(%s relowner) as rolname, "
+                                                 "relchecks, (reltriggers <> 0) as relhastriggers, "
                                                  "relhasindex, relhasrules, relhasoids, "
                                                  "d.refobjid as owning_tab, "
                                                  "d.refobjsubid as owning_col, "
@@ -3141,7 +3170,7 @@ getTables(int *numTables)
                                                  "SELECT c.tableoid, c.oid, relname, "
                                                  "relacl, relkind, relnamespace, "
                                                  "(%s relowner) as rolname, "
-                                                 "relchecks, reltriggers, "
+                                                 "relchecks, (reltriggers <> 0) as relhastriggers, "
                                                  "relhasindex, relhasrules, relhasoids, "
                                                  "d.refobjid as owning_tab, "
                                                  "d.refobjsubid as owning_col, "
@@ -3170,7 +3199,7 @@ getTables(int *numTables)
                                                  "SELECT c.tableoid, c.oid, relname, "
                                                  "relacl, relkind, relnamespace, "
                                                  "(%s relowner) as rolname, "
-                                                 "relchecks, reltriggers, "
+                                                 "relchecks, (reltriggers <> 0) as relhastriggers, "
                                                  "relhasindex, relhasrules, relhasoids, "
                                                  "d.refobjid as owning_tab, "
                                                  "d.refobjsubid as owning_col, "
@@ -3195,7 +3224,7 @@ getTables(int *numTables)
                                                  "SELECT tableoid, oid, relname, relacl, relkind, "
                                                  "0::oid as relnamespace, "
                                                  "(%s relowner) as rolname, "
-                                                 "relchecks, reltriggers, "
+                                                 "relchecks, (reltriggers <> 0) as relhastriggers, "
                                                  "relhasindex, relhasrules, relhasoids, "
                                                  "NULL::oid as owning_tab, "
                                                  "NULL::int4 as owning_col, "
@@ -3214,7 +3243,7 @@ getTables(int *numTables)
                                                  "SELECT tableoid, oid, relname, relacl, relkind, "
                                                  "0::oid as relnamespace, "
                                                  "(%s relowner) as rolname, "
-                                                 "relchecks, reltriggers, "
+                                                 "relchecks, (reltriggers <> 0) as relhastriggers, "
                                                  "relhasindex, relhasrules, "
                                                  "'t'::bool as relhasoids, "
                                                  "NULL::oid as owning_tab, "
@@ -3244,7 +3273,7 @@ getTables(int *numTables)
                                                  "ELSE relkind END AS relkind,"
                                                  "0::oid as relnamespace, "
                                                  "(%s relowner) as rolname, "
-                                                 "relchecks, reltriggers, "
+                                                 "relchecks, (reltriggers <> 0) as relhastriggers, "
                                                  "relhasindex, relhasrules, "
                                                  "'t'::bool as relhasoids, "
                                                  "NULL::oid as owning_tab, "
@@ -3285,7 +3314,7 @@ getTables(int *numTables)
        i_relkind = PQfnumber(res, "relkind");
        i_rolname = PQfnumber(res, "rolname");
        i_relchecks = PQfnumber(res, "relchecks");
-       i_reltriggers = PQfnumber(res, "reltriggers");
+       i_relhastriggers = PQfnumber(res, "relhastriggers");
        i_relhasindex = PQfnumber(res, "relhasindex");
        i_relhasrules = PQfnumber(res, "relhasrules");
        i_relhasoids = PQfnumber(res, "relhasoids");
@@ -3323,9 +3352,9 @@ getTables(int *numTables)
                tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
                tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
                tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
+               tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
                tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
                tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
-               tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
                if (PQgetisnull(res, i, i_owning_tab))
                {
                        tblinfo[i].owning_tab = InvalidOid;
@@ -3779,7 +3808,7 @@ getConstraints(TableInfo tblinfo[], int numTables)
        {
                TableInfo  *tbinfo = &tblinfo[i];
 
-               if (tbinfo->ntrig == 0 || !tbinfo->dobj.dump)
+               if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
                        continue;
 
                if (g_verbose)
@@ -4090,7 +4119,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
        {
                TableInfo  *tbinfo = &tblinfo[i];
 
-               if (tbinfo->ntrig == 0 || !tbinfo->dobj.dump)
+               if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
                        continue;
 
                if (g_verbose)
@@ -4177,16 +4206,6 @@ getTriggers(TableInfo tblinfo[], int numTables)
 
                ntups = PQntuples(res);
 
-               /*
-                * We may have less triggers than recorded due to having ignored
-                * foreign-key triggers
-                */
-               if (ntups > tbinfo->ntrig)
-               {
-                       write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
-                                         tbinfo->ntrig, tbinfo->dobj.name, ntups);
-                       exit_nicely();
-               }
                i_tableoid = PQfnumber(res, "tableoid");
                i_oid = PQfnumber(res, "oid");
                i_tgname = PQfnumber(res, "tgname");
index 2d66b32c639c320e445e7e8c0761616723f038b7..4a43ebc41044b70895fa854c907003dc9b8e18e1 100644 (file)
@@ -240,9 +240,9 @@ typedef struct _tableInfo
        char       *reloptions;         /* options specified by WITH (...) */
        bool            hasindex;               /* does it have any indexes? */
        bool            hasrules;               /* does it have any rules? */
+       bool            hastriggers;    /* does it have any triggers? */
        bool            hasoids;                /* does it have OIDs? */
        int                     ncheck;                 /* # of CHECK expressions */
-       int                     ntrig;                  /* # of triggers */
        /* these two are set only if table is a sequence owned by a column: */
        Oid                     owning_tab;             /* OID of table owning sequence */
        int                     owning_col;             /* attr # of column owning sequence */
index 71b11831079066521d5ab9c93f17630109b1672b..c1e1913040ecedd38da546cf5db41b57c6b4c7b3 100644 (file)
@@ -840,10 +840,10 @@ describeOneTableDetails(const char *schemaname,
        struct
        {
                int16           checks;
-               int16           triggers;
                char            relkind;
                bool            hasindex;
                bool            hasrules;
+               bool            hastriggers;
                bool            hasoids;
                Oid                     tablespace;
        }                       tableinfo;
@@ -861,9 +861,10 @@ describeOneTableDetails(const char *schemaname,
 
        /* Get general table info */
        printfPQExpBuffer(&buf,
-          "SELECT relhasindex, relkind, relchecks, reltriggers, relhasrules, "
+          "SELECT relchecks, relkind, relhasindex, relhasrules, %s, "
                                          "relhasoids%s\n"
                                          "FROM pg_catalog.pg_class WHERE oid = '%s'",
+                                         (pset.sversion >= 80400 ? "relhastriggers" : "reltriggers <> 0"),
                                          (pset.sversion >= 80000 ? ", reltablespace" : ""),
                                          oid);
        res = PSQLexec(buf.data, false);
@@ -879,11 +880,11 @@ describeOneTableDetails(const char *schemaname,
                goto error_return;
        }
 
-       tableinfo.checks = atoi(PQgetvalue(res, 0, 2));
-       tableinfo.triggers = atoi(PQgetvalue(res, 0, 3));
+       tableinfo.checks = atoi(PQgetvalue(res, 0, 0));
        tableinfo.relkind = *(PQgetvalue(res, 0, 1));
-       tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 0), "t") == 0;
-       tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
+       tableinfo.hasindex = strcmp(PQgetvalue(res, 0, 2), "t") == 0;
+       tableinfo.hasrules = strcmp(PQgetvalue(res, 0, 3), "t") == 0;
+       tableinfo.hastriggers = strcmp(PQgetvalue(res, 0, 4), "t") == 0;
        tableinfo.hasoids = strcmp(PQgetvalue(res, 0, 5), "t") == 0;
        tableinfo.tablespace = (pset.sversion >= 80000) ?
                                                                atooid(PQgetvalue(res, 0, 6)) : 0;
@@ -1287,7 +1288,7 @@ describeOneTableDetails(const char *schemaname,
                }
 
                /* print foreign-key constraints (there are none if no triggers) */
-               if (tableinfo.triggers)
+               if (tableinfo.hastriggers)
                {
                        printfPQExpBuffer(&buf,
                                                          "SELECT conname,\n"
@@ -1318,7 +1319,7 @@ describeOneTableDetails(const char *schemaname,
                }
 
                /* print incoming foreign-key references (none if no triggers) */
-               if (tableinfo.triggers)
+               if (tableinfo.hastriggers)
                {
                        printfPQExpBuffer(&buf,
                                                          "SELECT conname, conrelid::pg_catalog.regclass,\n"
@@ -1446,7 +1447,7 @@ describeOneTableDetails(const char *schemaname,
                }
 
                /* print triggers (but ignore foreign-key triggers) */
-               if (tableinfo.triggers)
+               if (tableinfo.hastriggers)
                {
                        printfPQExpBuffer(&buf,
                                                          "SELECT t.tgname, "
index a88d830e7e8a1bff364dcbe207ac6cfc2db8f4d9..9bb3c681aefc63d29ece78c20520df56c34d9290 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200811041
+#define CATALOG_VERSION_NO     200811091
 
 #endif
index 65605a726b977f090cb2a94e1146339ada0b18ec..33e90fc64148631a818b667cf5dafd5924e91747 100644 (file)
@@ -409,17 +409,14 @@ DATA(insert ( 1249 tableoid                       26 0  4  -7 0 -1 -1 t p i t f f t 0));
 { 1259, {"relkind"},      18, -1,      1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
 { 1259, {"relnatts"},     21, -1,      2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
 { 1259, {"relchecks"},    21, -1,      2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
-{ 1259, {"reltriggers"},   21, -1,     2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
-{ 1259, {"relukeys"},     21, -1,      2, 18, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
-{ 1259, {"relfkeys"},     21, -1,      2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
-{ 1259, {"relrefs"},      21, -1,      2, 20, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
-{ 1259, {"relhasoids"},    16, -1,     1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
-{ 1259, {"relhaspkey"},    16, -1,     1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
-{ 1259, {"relhasrules"},   16, -1,     1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
-{ 1259, {"relhassubclass"},16, -1,     1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
-{ 1259, {"relfrozenxid"},  28, -1,     4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
-{ 1259, {"relacl"},             1034, -1, -1, 26, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
-{ 1259, {"reloptions"},  1009, -1, -1, 27, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
+{ 1259, {"relhasoids"},    16, -1,     1, 17, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
+{ 1259, {"relhaspkey"},    16, -1,     1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
+{ 1259, {"relhasrules"},   16, -1,     1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
+{ 1259, {"relhastriggers"},16, -1,     1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
+{ 1259, {"relhassubclass"},16, -1,     1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
+{ 1259, {"relfrozenxid"},  28, -1,     4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
+{ 1259, {"relacl"},             1034, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
+{ 1259, {"reloptions"},  1009, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
 
 DATA(insert ( 1259 relname                     19 -1 NAMEDATALEN       1 0 -1 -1 f p c t f f t 0));
 DATA(insert ( 1259 relnamespace                26 -1 4   2 0 -1 -1 t p i t f f t 0));
@@ -437,17 +434,14 @@ DATA(insert ( 1259 relisshared            16 -1 1  13 0 -1 -1 t p c t f f t 0));
 DATA(insert ( 1259 relkind                     18 -1 1  14 0 -1 -1 t p c t f f t 0));
 DATA(insert ( 1259 relnatts                    21 -1 2  15 0 -1 -1 t p s t f f t 0));
 DATA(insert ( 1259 relchecks           21 -1 2  16 0 -1 -1 t p s t f f t 0));
-DATA(insert ( 1259 reltriggers         21 -1 2  17 0 -1 -1 t p s t f f t 0));
-DATA(insert ( 1259 relukeys                    21 -1 2  18 0 -1 -1 t p s t f f t 0));
-DATA(insert ( 1259 relfkeys                    21 -1 2  19 0 -1 -1 t p s t f f t 0));
-DATA(insert ( 1259 relrefs                     21 -1 2  20 0 -1 -1 t p s t f f t 0));
-DATA(insert ( 1259 relhasoids          16 -1 1  21 0 -1 -1 t p c t f f t 0));
-DATA(insert ( 1259 relhaspkey          16 -1 1  22 0 -1 -1 t p c t f f t 0));
-DATA(insert ( 1259 relhasrules         16 -1 1  23 0 -1 -1 t p c t f f t 0));
-DATA(insert ( 1259 relhassubclass      16 -1 1  24 0 -1 -1 t p c t f f t 0));
-DATA(insert ( 1259 relfrozenxid                28 -1 4  25 0 -1 -1 t p i t f f t 0));
-DATA(insert ( 1259 relacl                1034 -1 -1 26 1 -1 -1 f x i f f f t 0));
-DATA(insert ( 1259 reloptions    1009 -1 -1 27 1 -1 -1 f x i f f f t 0));
+DATA(insert ( 1259 relhasoids          16 -1 1  17 0 -1 -1 t p c t f f t 0));
+DATA(insert ( 1259 relhaspkey          16 -1 1  18 0 -1 -1 t p c t f f t 0));
+DATA(insert ( 1259 relhasrules         16 -1 1  19 0 -1 -1 t p c t f f t 0));
+DATA(insert ( 1259 relhastriggers      16 -1 1  20 0 -1 -1 t p c t f f t 0));
+DATA(insert ( 1259 relhassubclass      16 -1 1  21 0 -1 -1 t p c t f f t 0));
+DATA(insert ( 1259 relfrozenxid                28 -1 4  22 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1259 relacl                1034 -1 -1 23 1 -1 -1 f x i f f f t 0));
+DATA(insert ( 1259 reloptions    1009 -1 -1 24 1 -1 -1 f x i f f f t 0));
 DATA(insert ( 1259 ctid                                27 0  6  -1 0 -1 -1 f p s t f f t 0));
 DATA(insert ( 1259 oid                         26 0  4  -2 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 xmin                                28 0  4  -3 0 -1 -1 t p i t f f t 0));
index 6e3886ea3fec41d94de8422cc569af7b16b3ce2d..f0c84f37012f1bd18200cf28d9e4fa73f46f99e0 100644 (file)
@@ -52,14 +52,11 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP
         * contain entries with negative attnums for system attributes.
         */
        int2            relchecks;              /* # of CHECK constraints for class */
-       int2            reltriggers;    /* # of TRIGGERs */
-       int2            relukeys;               /* # of Unique keys (not used) */
-       int2            relfkeys;               /* # of FOREIGN KEYs (not used) */
-       int2            relrefs;                /* # of references to this rel (not used) */
        bool            relhasoids;             /* T if we generate OIDs for rows of rel */
-       bool            relhaspkey;             /* has PRIMARY KEY index */
-       bool            relhasrules;    /* has associated rules */
-       bool            relhassubclass; /* has derived classes */
+       bool            relhaspkey;             /* has (or has had) PRIMARY KEY index */
+       bool            relhasrules;    /* has (or has had) any rules */
+       bool            relhastriggers; /* has (or has had) any TRIGGERs */
+       bool            relhassubclass; /* has (or has had) derived classes */
        TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */
 
        /*
@@ -88,7 +85,7 @@ typedef FormData_pg_class *Form_pg_class;
  * ----------------
  */
 
-#define Natts_pg_class                                 27
+#define Natts_pg_class                                 24
 #define Anum_pg_class_relname                  1
 #define Anum_pg_class_relnamespace             2
 #define Anum_pg_class_reltype                  3
@@ -105,17 +102,14 @@ typedef FormData_pg_class *Form_pg_class;
 #define Anum_pg_class_relkind                  14
 #define Anum_pg_class_relnatts                 15
 #define Anum_pg_class_relchecks                        16
-#define Anum_pg_class_reltriggers              17
-#define Anum_pg_class_relukeys                 18
-#define Anum_pg_class_relfkeys                 19
-#define Anum_pg_class_relrefs                  20
-#define Anum_pg_class_relhasoids               21
-#define Anum_pg_class_relhaspkey               22
-#define Anum_pg_class_relhasrules              23
-#define Anum_pg_class_relhassubclass   24
-#define Anum_pg_class_relfrozenxid             25
-#define Anum_pg_class_relacl                   26
-#define Anum_pg_class_reloptions               27
+#define Anum_pg_class_relhasoids               17
+#define Anum_pg_class_relhaspkey               18
+#define Anum_pg_class_relhasrules              19
+#define Anum_pg_class_relhastriggers   20
+#define Anum_pg_class_relhassubclass   21
+#define Anum_pg_class_relfrozenxid             22
+#define Anum_pg_class_relacl                   23
+#define Anum_pg_class_reloptions               24
 
 /* ----------------
  *             initial contents of pg_class
@@ -127,13 +121,13 @@ typedef FormData_pg_class *Form_pg_class;
  */
 
 /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
-DATA(insert OID = 1247 (  pg_type              PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 0 0 0 0 t f f f 3   _null_ _null_ ));
+DATA(insert OID = 1247 (  pg_type              PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1249 (  pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1249 (  pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1255 (  pg_proc              PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 22 0 0 0 0 0 t f f f 3 _null_ _null_ ));
+DATA(insert OID = 1255 (  pg_proc              PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 22 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1259 (  pg_class             PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 27 0 0 0 0 0 t f f f 3 _null_ _null_ ));
+DATA(insert OID = 1259 (  pg_class             PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
 DESCR("");
 
 #define                  RELKIND_INDEX                   'i'           /* secondary index */
index 50abeb5b0e0e9895cff1956dd1fcfa17764f6a0d..80b002d5388440df5d0b0ad5edf000b474c9519f 100644 (file)
@@ -1309,7 +1309,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE ((pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_sequences.schemaname !~ '^pg_toast'::text));
  pg_statio_user_tables    | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE ((pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (pg_statio_all_tables.schemaname !~ '^pg_toast'::text));
  pg_stats                 | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stavalues1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stavalues2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stavalues3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE WHEN (s.stakind1 = ANY (ARRAY[1, 4])) THEN s.stanumbers1 WHEN (s.stakind2 = ANY (ARRAY[1, 4])) THEN s.stanumbers2 WHEN (s.stakind3 = ANY (ARRAY[1, 4])) THEN s.stanumbers3 WHEN (s.stakind4 = ANY (ARRAY[1, 4])) THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE WHEN (s.stakind1 = 2) THEN s.stavalues1 WHEN (s.stakind2 = 2) THEN s.stavalues2 WHEN (s.stakind3 = 2) THEN s.stavalues3 WHEN (s.stakind4 = 2) THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE WHEN (s.stakind1 = 3) THEN s.stanumbers1[1] WHEN (s.stakind2 = 3) THEN s.stanumbers2[1] WHEN (s.stakind3 = 3) THEN s.stanumbers3[1] WHEN (s.stakind4 = 3) THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE has_table_privilege(c.oid, 'select'::text);
- pg_tables                | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS tablespace, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, (c.reltriggers > 0) AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char");
+ pg_tables                | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS tablespace, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, c.relhastriggers AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char");
  pg_timezone_abbrevs      | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst);
  pg_timezone_names        | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst);
  pg_user                  | SELECT pg_shadow.usename, pg_shadow.usesysid, pg_shadow.usecreatedb, pg_shadow.usesuper, pg_shadow.usecatupd, '********'::text AS passwd, pg_shadow.valuntil, pg_shadow.useconfig FROM pg_shadow;