diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index df9735089aa..ea778de3360 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -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,32 +174,19 @@ 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 - */ - if (strcmp(NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname), - StatisticRelationName) == 0) - { - ReleaseSysCache(tuple); - CommitTransactionCommand(); - return; - } - ReleaseSysCache(tuple); - /* * Open the class, getting only a read lock on it, and check * permissions. Permissions check should match vacuum's check! */ - onerel = heap_open(relid, AccessShareLock); + onerel = relation_open(relid, AccessShareLock); if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) || (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared))) @@ -207,12 +195,40 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) if (!vacstmt->vacuum) elog(WARNING, "Skipping \"%s\" --- only table or database owner can ANALYZE it", RelationGetRelationName(onerel)); - heap_close(onerel, NoLock); + relation_close(onerel, AccessShareLock); CommitTransactionCommand(); return; } - elog(elevel, "Analyzing %s", RelationGetRelationName(onerel)); + /* + * 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 != RELKIND_RELATION) + { + /* No need for a WARNING if we already complained during VACUUM */ + if (!vacstmt->vacuum) + elog(WARNING, "Skipping \"%s\" --- can not process indexes, views or special system tables", + RelationGetRelationName(onerel)); + 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.%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(); diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 6553529cdcf..fff0320eca2 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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" @@ -40,19 +41,12 @@ #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; + List *vrl = NIL; + MemoryContext oldcontext; - if (VacRelP) + 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)); - } + /* Process all plain relations listed in pg_class */ + Relation pgclass; + HeapScanDesc scan; + HeapTuple tuple; + ScanKeyData key; - vrl = cur = (VRelList) NULL; + ScanKeyEntryInitialize(&key, 0x0, + Anum_pg_class_relkind, + F_CHAREQ, + CharGetDatum(RELKIND_RELATION)); - rel = heap_openr(RelationRelationName, AccessShareLock); - tupdesc = RelationGetDescr(rel); + pgclass = heap_openr(RelationRelationName, AccessShareLock); - scan = heap_beginscan(rel, false, SnapshotNow, 1, &key); + scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) - { - d = heap_getattr(tuple, Anum_pg_class_relname, tupdesc, &n); - rname = (char *) DatumGetName(d); - - d = heap_getattr(tuple, Anum_pg_class_relkind, tupdesc, &n); - rkind = DatumGetChar(d); - - if (rkind != RELKIND_RELATION) + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { - elog(WARNING, "%s: can not process indexes, views or special system tables", - stmttype); - continue; + /* Make a relation list entry for this guy */ + oldcontext = MemoryContextSwitchTo(vac_context); + vrl = lappendi(vrl, tuple->t_data->t_oid); + MemoryContextSwitchTo(oldcontext); } - /* Make a relation list entry for this guy */ - if (vrl == (VRelList) NULL) - vrl = cur = (VRelList) - MemoryContextAlloc(vac_context, sizeof(VRelListData)); - else - { - cur->vrl_next = (VRelList) - MemoryContextAlloc(vac_context, sizeof(VRelListData)); - cur = cur->vrl_next; - } - - 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; diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 516fe35f2a9..b7da9f5bbb0 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -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; diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index b073e514573..f9accfefc24 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -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 $ * * ---------- */ @@ -33,11 +33,10 @@ #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)); diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 6ec682f5206..bf0981e6372 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -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 ---------- */ /* diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 90130178ca1..cb2d7cfdf68 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -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')