]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Make VACUUM handle schema-qualified relation names properly.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 2 Apr 2002 01:03:07 +0000 (01:03 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 2 Apr 2002 01:03:07 +0000 (01:03 +0000)
src/backend/commands/analyze.c
src/backend/commands/vacuum.c
src/backend/commands/vacuumlazy.c
src/backend/utils/adt/ri_triggers.c
src/backend/utils/cache/lsyscache.c
src/include/utils/lsyscache.h

index df9735089aab470a10a334753db3e7d12649c586..ea778de3360444d2f330ab8c12192825614fc3cd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.29 2002/03/21 23:27:20 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.30 2002/04/02 01:03:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@
 #include "access/tuptoaster.h"
 #include "catalog/catname.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_namespace.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
@@ -30,6 +31,7 @@
 #include "utils/builtins.h"
 #include "utils/datum.h"
 #include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/tuplesort.h"
 
@@ -147,7 +149,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
                                numrows;
        double          totalrows;
        HeapTuple  *rows;
-       HeapTuple       tuple;
 
        if (vacstmt->verbose)
                elevel = INFO;
@@ -173,46 +174,61 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
         * Race condition -- if the pg_class tuple has gone away since the
         * last time we saw it, we don't need to process it.
         */
-       tuple = SearchSysCache(RELOID,
-                                                  ObjectIdGetDatum(relid),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
+       if (!SearchSysCacheExists(RELOID,
+                                                         ObjectIdGetDatum(relid),
+                                                         0, 0, 0))
        {
                CommitTransactionCommand();
                return;
        }
 
        /*
-        * We can ANALYZE any table except pg_statistic. See update_attstats
+        * Open the class, getting only a read lock on it, and check
+        * permissions. Permissions check should match vacuum's check!
         */
-       if (strcmp(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname),
-                          StatisticRelationName) == 0)
+       onerel = relation_open(relid, AccessShareLock);
+
+       if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
+                 (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
        {
-               ReleaseSysCache(tuple);
+               /* No need for a WARNING if we already complained during VACUUM */
+               if (!vacstmt->vacuum)
+                       elog(WARNING, "Skipping \"%s\" --- only table or database owner can ANALYZE it",
+                                RelationGetRelationName(onerel));
+               relation_close(onerel, AccessShareLock);
                CommitTransactionCommand();
                return;
        }
-       ReleaseSysCache(tuple);
 
        /*
-        * Open the class, getting only a read lock on it, and check
-        * permissions. Permissions check should match vacuum's check!
+        * Check that it's a plain table; we used to do this in getrels() but
+        * seems safer to check after we've locked the relation.
         */
-       onerel = heap_open(relid, AccessShareLock);
-
-       if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
-                 (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
+       if (onerel->rd_rel->relkind != RELKIND_RELATION)
        {
                /* No need for a WARNING if we already complained during VACUUM */
                if (!vacstmt->vacuum)
-                       elog(WARNING, "Skipping \"%s\" --- only table or database owner can ANALYZE it",
+                       elog(WARNING, "Skipping \"%s\" --- can not process indexes, views or special system tables",
                                 RelationGetRelationName(onerel));
-               heap_close(onerel, NoLock);
+               relation_close(onerel, AccessShareLock);
+               CommitTransactionCommand();
+               return;
+       }
+
+       /*
+        * We can ANALYZE any table except pg_statistic. See update_attstats
+        */
+       if (RelationGetNamespace(onerel) == PG_CATALOG_NAMESPACE &&
+               strcmp(RelationGetRelationName(onerel), StatisticRelationName) == 0)
+       {
+               relation_close(onerel, AccessShareLock);
                CommitTransactionCommand();
                return;
        }
 
-       elog(elevel, "Analyzing %s", RelationGetRelationName(onerel));
+       elog(elevel, "Analyzing %s.%s",
+                get_namespace_name(RelationGetNamespace(onerel)),
+                RelationGetRelationName(onerel));
 
        /*
         * Determine which columns to analyze
@@ -266,7 +282,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
         */
        if (attr_cnt <= 0)
        {
-               heap_close(onerel, NoLock);
+               relation_close(onerel, NoLock);
                CommitTransactionCommand();
                return;
        }
@@ -353,7 +369,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
         * before we commit.  (If someone did, they'd fail to clean up the
         * entries we made in pg_statistic.)
         */
-       heap_close(onerel, NoLock);
+       relation_close(onerel, NoLock);
 
        /* Commit and release working memory */
        CommitTransactionCommand();
index 6553529cdcf810e5b082c78a8b8f570ba9c0b0ca..fff0320eca2a17a48182239bdb0c12bc5b4330c9 100644 (file)
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.220 2002/03/31 06:26:30 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.221 2002/04/02 01:03:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,6 +27,7 @@
 #include "access/xlog.h"
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
+#include "catalog/namespace.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_index.h"
 #include "commands/vacuum.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/inval.h"
+#include "utils/lsyscache.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
 #include "pgstat.h"
 
 
-typedef struct VRelListData
-{
-       Oid                     vrl_relid;
-       struct VRelListData *vrl_next;
-} VRelListData;
-
-typedef VRelListData *VRelList;
-
 typedef struct VacPageData
 {
        BlockNumber blkno;                      /* BlockNumber of this Page */
@@ -118,13 +112,13 @@ static TransactionId initialFreezeLimit;
 /* non-export function prototypes */
 static void vacuum_init(VacuumStmt *vacstmt);
 static void vacuum_shutdown(VacuumStmt *vacstmt);
-static VRelList getrels(Name VacRelP, const char *stmttype);
+static List *getrels(const RangeVar *vacrel, const char *stmttype);
 static void vac_update_dbstats(Oid dbid,
                                   TransactionId vacuumXID,
                                   TransactionId frozenXID);
 static void vac_truncate_clog(TransactionId vacuumXID,
                                  TransactionId frozenXID);
-static void vacuum_rel(Oid relid, VacuumStmt *vacstmt);
+static void vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind);
 static void full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
 static void scan_heap(VRelStats *vacrelstats, Relation onerel,
                  VacPageList vacuum_pages, VacPageList fraged_pages);
@@ -167,10 +161,13 @@ void
 vacuum(VacuumStmt *vacstmt)
 {
        const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
-       NameData        VacRel;
-       Name            VacRelName;
-       VRelList        vrl,
-                               cur;
+       List       *vrl,
+                          *cur;
+
+       if (vacstmt->verbose)
+               elevel = INFO;
+       else
+               elevel = DEBUG1;
 
        /*
         * We cannot run VACUUM inside a user transaction block; if we were
@@ -189,11 +186,6 @@ vacuum(VacuumStmt *vacstmt)
         */
        pgstat_vacuum_tabstat();
 
-       if (vacstmt->verbose)
-               elevel = INFO;
-       else
-               elevel = DEBUG1;
-
        /*
         * Create special memory context for cross-transaction storage.
         *
@@ -207,17 +199,8 @@ vacuum(VacuumStmt *vacstmt)
                                                                                ALLOCSET_DEFAULT_INITSIZE,
                                                                                ALLOCSET_DEFAULT_MAXSIZE);
 
-       /* Convert relname, which is just a string, to a Name */
-       if (vacstmt->relation)
-       {
-               namestrcpy(&VacRel, vacstmt->relation->relname);
-               VacRelName = &VacRel;
-       }
-       else
-               VacRelName = NULL;
-
        /* Build list of relations to process (note this lives in vac_context) */
-       vrl = getrels(VacRelName, stmttype);
+       vrl = getrels(vacstmt->relation, stmttype);
 
        /*
         * Start up the vacuum cleaner.
@@ -231,12 +214,14 @@ vacuum(VacuumStmt *vacstmt)
         * ANALYZE part runs as a separate transaction from the VACUUM to
         * further reduce locking.
         */
-       for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
+       foreach(cur, vrl)
        {
+               Oid             relid = (Oid) lfirsti(cur);
+
                if (vacstmt->vacuum)
-                       vacuum_rel(cur->vrl_relid, vacstmt);
+                       vacuum_rel(relid, vacstmt, RELKIND_RELATION);
                if (vacstmt->analyze)
-                       analyze_rel(cur->vrl_relid, vacstmt);
+                       analyze_rel(relid, vacstmt);
        }
 
        /* clean up */
@@ -323,86 +308,58 @@ vacuum_shutdown(VacuumStmt *vacstmt)
 }
 
 /*
- * Build a list of VRelListData nodes for each relation to be processed
+ * Build a list of Oids for each relation to be processed
  *
  * The list is built in vac_context so that it will survive across our
  * per-relation transactions.
  */
-static VRelList
-getrels(Name VacRelP, const char *stmttype)
+static List *
+getrels(const RangeVar *vacrel, const char *stmttype)
 {
-       Relation        rel;
-       TupleDesc       tupdesc;
-       HeapScanDesc scan;
-       HeapTuple       tuple;
-       VRelList        vrl,
-                               cur;
-       Datum           d;
-       char       *rname;
-       char            rkind;
-       bool            n;
-       ScanKeyData key;
-
-       if (VacRelP)
+       List       *vrl = NIL;
+       MemoryContext oldcontext;
+
+       if (vacrel)
        {
-               /*
-                * we could use the cache here, but it is clearer to use scankeys
-                * for both vacuum cases, bjm 2000/01/19
-                */
-               ScanKeyEntryInitialize(&key, 0x0, Anum_pg_class_relname,
-                                                          F_NAMEEQ,
-                                                          PointerGetDatum(NameStr(*VacRelP)));
+               /* Process specific relation */
+               Oid             relid;
+
+               relid = RangeVarGetRelid(vacrel, false);
+
+               /* Make a relation list entry for this guy */
+               oldcontext = MemoryContextSwitchTo(vac_context);
+               vrl = lappendi(vrl, relid);
+               MemoryContextSwitchTo(oldcontext);
        }
        else
        {
-               /* find all plain relations listed in pg_class */
-               ScanKeyEntryInitialize(&key, 0x0, Anum_pg_class_relkind,
-                                                          F_CHAREQ, CharGetDatum(RELKIND_RELATION));
-       }
-
-       vrl = cur = (VRelList) NULL;
-
-       rel = heap_openr(RelationRelationName, AccessShareLock);
-       tupdesc = RelationGetDescr(rel);
-
-       scan = heap_beginscan(rel, false, SnapshotNow, 1, &key);
+               /* Process all plain relations listed in pg_class */
+               Relation        pgclass;
+               HeapScanDesc scan;
+               HeapTuple       tuple;
+               ScanKeyData key;
 
-       while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
-       {
-               d = heap_getattr(tuple, Anum_pg_class_relname, tupdesc, &n);
-               rname = (char *) DatumGetName(d);
+               ScanKeyEntryInitialize(&key, 0x0,
+                                                          Anum_pg_class_relkind,
+                                                          F_CHAREQ,
+                                                          CharGetDatum(RELKIND_RELATION));
 
-               d = heap_getattr(tuple, Anum_pg_class_relkind, tupdesc, &n);
-               rkind = DatumGetChar(d);
+               pgclass = heap_openr(RelationRelationName, AccessShareLock);
 
-               if (rkind != RELKIND_RELATION)
-               {
-                       elog(WARNING, "%s: can not process indexes, views or special system tables",
-                                stmttype);
-                       continue;
-               }
+               scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key);
 
-               /* Make a relation list entry for this guy */
-               if (vrl == (VRelList) NULL)
-                       vrl = cur = (VRelList)
-                               MemoryContextAlloc(vac_context, sizeof(VRelListData));
-               else
+               while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
                {
-                       cur->vrl_next = (VRelList)
-                               MemoryContextAlloc(vac_context, sizeof(VRelListData));
-                       cur = cur->vrl_next;
+                       /* Make a relation list entry for this guy */
+                       oldcontext = MemoryContextSwitchTo(vac_context);
+                       vrl = lappendi(vrl, tuple->t_data->t_oid);
+                       MemoryContextSwitchTo(oldcontext);
                }
 
-               cur->vrl_relid = tuple->t_data->t_oid;
-               cur->vrl_next = (VRelList) NULL;
+               heap_endscan(scan);
+               heap_close(pgclass, AccessShareLock);
        }
 
-       heap_endscan(scan);
-       heap_close(rel, AccessShareLock);
-
-       if (vrl == NULL)
-               elog(WARNING, "%s: table not found", stmttype);
-
        return vrl;
 }
 
@@ -663,7 +620,7 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
  *             At entry and exit, we are not inside a transaction.
  */
 static void
-vacuum_rel(Oid relid, VacuumStmt *vacstmt)
+vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
 {
        LOCKMODE        lmode;
        Relation        onerel;
@@ -710,14 +667,27 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
         * Note we choose to treat permissions failure as a WARNING and keep
         * trying to vacuum the rest of the DB --- is this appropriate?
         */
-       onerel = heap_open(relid, lmode);
+       onerel = relation_open(relid, lmode);
 
        if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
                  (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
        {
                elog(WARNING, "Skipping \"%s\" --- only table or database owner can VACUUM it",
                         RelationGetRelationName(onerel));
-               heap_close(onerel, lmode);
+               relation_close(onerel, lmode);
+               CommitTransactionCommand();
+               return;
+       }
+
+       /*
+        * Check that it's a plain table; we used to do this in getrels() but
+        * seems safer to check after we've locked the relation.
+        */
+       if (onerel->rd_rel->relkind != expected_relkind)
+       {
+               elog(WARNING, "Skipping \"%s\" --- can not process indexes, views or special system tables",
+                        RelationGetRelationName(onerel));
+               relation_close(onerel, lmode);
                CommitTransactionCommand();
                return;
        }
@@ -749,7 +719,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
                lazy_vacuum_rel(onerel, vacstmt);
 
        /* all done with this class, but hold lock until commit */
-       heap_close(onerel, NoLock);
+       relation_close(onerel, NoLock);
 
        /*
         * Complete the transaction and free all temporary memory used.
@@ -764,7 +734,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
         * statistics are totally unimportant for toast relations.
         */
        if (toast_relid != InvalidOid)
-               vacuum_rel(toast_relid, vacstmt);
+               vacuum_rel(toast_relid, vacstmt, RELKIND_TOASTVALUE);
 
        /*
         * Now release the session-level lock on the master table.
@@ -954,7 +924,9 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
        vac_init_rusage(&ru0);
 
        relname = RelationGetRelationName(onerel);
-       elog(elevel, "--Relation %s--", relname);
+       elog(elevel, "--Relation %s.%s--",
+                get_namespace_name(RelationGetNamespace(onerel)),
+                relname);
 
        empty_pages = new_pages = changed_pages = empty_end_pages = 0;
        num_tuples = tups_vacuumed = nkeep = nunused = 0;
index 516fe35f2a9a9783a71bff0aadec476c8069d864..b7da9f5bbb05542c66e905c7586046e50a67d71b 100644 (file)
@@ -31,7 +31,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.13 2002/03/06 06:09:38 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/vacuumlazy.c,v 1.14 2002/04/02 01:03:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -45,6 +45,7 @@
 #include "storage/freespace.h"
 #include "storage/sinval.h"
 #include "storage/smgr.h"
+#include "utils/lsyscache.h"
 
 
 /*
@@ -207,7 +208,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
        vac_init_rusage(&ru0);
 
        relname = RelationGetRelationName(onerel);
-       elog(elevel, "--Relation %s--", relname);
+       elog(elevel, "--Relation %s.%s--",
+                get_namespace_name(RelationGetNamespace(onerel)),
+                relname);
 
        empty_pages = changed_pages = 0;
        num_tuples = tups_vacuumed = nkeep = nunused = 0;
index b073e51457328e442bdfc4798354982fa936521c..f9accfefc241dfd3bc416e57d027c5c62ac8737c 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
  * Copyright 1999 Jan Wieck
  *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.35 2002/04/01 22:36:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.36 2002/04/02 01:03:07 tgl Exp $
  *
  * ----------
  */
 
 #include "postgres.h"
 
-#include "catalog/pg_namespace.h"
 #include "catalog/pg_operator.h"
 #include "commands/trigger.h"
 #include "executor/spi_priv.h"
-#include "nodes/makefuncs.h"
+#include "utils/lsyscache.h"
 #include "miscadmin.h"
 
 
@@ -2954,18 +2953,7 @@ quoteOneName(char *buffer, const char *name)
 static void
 quoteRelationName(char *buffer, Relation rel)
 {
-       HeapTuple       tuple;
-       char       *nsname;
-
-       tuple = SearchSysCache(NAMESPACEOID,
-                                                  ObjectIdGetDatum(RelationGetNamespace(rel)),
-                                                  0, 0, 0);
-       if (!HeapTupleIsValid(tuple))
-               elog(ERROR, "Failed to lookup namespace %u of relation %s",
-                        RelationGetNamespace(rel), RelationGetRelationName(rel));
-       nsname = NameStr(((Form_pg_namespace) GETSTRUCT(tuple))->nspname);
-       quoteOneName(buffer, nsname);
-       ReleaseSysCache(tuple);
+       quoteOneName(buffer, get_namespace_name(RelationGetNamespace(rel)));
        buffer += strlen(buffer);
        *buffer++ = '.';
        quoteOneName(buffer, RelationGetRelationName(rel));
index 6ec682f5206d045576ba4490423a762e5587afa4..bf0981e6372182b8c80ca319c2768b797b25fdcd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.67 2002/03/29 19:06:15 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.68 2002/04/02 01:03:07 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -17,6 +17,7 @@
 
 #include "access/tupmacs.h"
 #include "catalog/pg_amop.h"
+#include "catalog/pg_namespace.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
@@ -1279,6 +1280,35 @@ free_attstatsslot(Oid atttype,
                pfree(numbers);
 }
 
+/*                             ---------- PG_NAMESPACE CACHE ----------                                 */
+
+/*
+ * get_namespace_name
+ *             Returns the name of a given namespace
+ *
+ * Returns a palloc'd copy of the string, or NULL if no such namespace.
+ */
+char *
+get_namespace_name(Oid nspid)
+{
+       HeapTuple       tp;
+
+       tp = SearchSysCache(NAMESPACEOID,
+                                               ObjectIdGetDatum(nspid),
+                                               0, 0, 0);
+       if (HeapTupleIsValid(tp))
+       {
+               Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
+               char       *result;
+
+               result = pstrdup(NameStr(nsptup->nspname));
+               ReleaseSysCache(tp);
+               return result;
+       }
+       else
+               return NULL;
+}
+
 /*                             ---------- PG_SHADOW CACHE ----------                                    */
 
 /*
index 90130178ca183d5a6bc6290e9b9d21b5a8654348..cb2d7cfdf68072d3687f8aeb03deca2f739df4ab 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: lsyscache.h,v 1.47 2002/03/29 19:06:26 tgl Exp $
+ * $Id: lsyscache.h,v 1.48 2002/04/02 01:03:07 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,7 @@ extern bool get_attstatsslot(HeapTuple statstuple,
 extern void free_attstatsslot(Oid atttype,
                                  Datum *values, int nvalues,
                                  float4 *numbers, int nnumbers);
+extern char *get_namespace_name(Oid nspid);
 extern int32 get_usesysid(const char *username);
 
 #define TypeIsToastable(typid) (get_typstorage(typid) != 'p')