Commit 1dc43ea7 authored by Tom Lane's avatar Tom Lane

Make VACUUM handle schema-qualified relation names properly.

parent 789ddcb5
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -20,6 +20,7 @@
#include "access/tuptoaster.h" #include "access/tuptoaster.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_statistic.h" #include "catalog/pg_statistic.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/datum.h" #include "utils/datum.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/tuplesort.h" #include "utils/tuplesort.h"
...@@ -147,7 +149,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -147,7 +149,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
numrows; numrows;
double totalrows; double totalrows;
HeapTuple *rows; HeapTuple *rows;
HeapTuple tuple;
if (vacstmt->verbose) if (vacstmt->verbose)
elevel = INFO; elevel = INFO;
...@@ -173,46 +174,61 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -173,46 +174,61 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
* Race condition -- if the pg_class tuple has gone away since the * Race condition -- if the pg_class tuple has gone away since the
* last time we saw it, we don't need to process it. * last time we saw it, we don't need to process it.
*/ */
tuple = SearchSysCache(RELOID, if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(relid), ObjectIdGetDatum(relid),
0, 0, 0); 0, 0, 0))
if (!HeapTupleIsValid(tuple))
{ {
CommitTransactionCommand(); CommitTransactionCommand();
return; 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), onerel = relation_open(relid, AccessShareLock);
StatisticRelationName) == 0)
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(); CommitTransactionCommand();
return; return;
} }
ReleaseSysCache(tuple);
/* /*
* Open the class, getting only a read lock on it, and check * Check that it's a plain table; we used to do this in getrels() but
* permissions. Permissions check should match vacuum's check! * seems safer to check after we've locked the relation.
*/ */
onerel = heap_open(relid, AccessShareLock); if (onerel->rd_rel->relkind != RELKIND_RELATION)
if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
{ {
/* No need for a WARNING if we already complained during VACUUM */ /* No need for a WARNING if we already complained during VACUUM */
if (!vacstmt->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)); 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(); CommitTransactionCommand();
return; return;
} }
elog(elevel, "Analyzing %s", RelationGetRelationName(onerel)); elog(elevel, "Analyzing %s.%s",
get_namespace_name(RelationGetNamespace(onerel)),
RelationGetRelationName(onerel));
/* /*
* Determine which columns to analyze * Determine which columns to analyze
...@@ -266,7 +282,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -266,7 +282,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
*/ */
if (attr_cnt <= 0) if (attr_cnt <= 0)
{ {
heap_close(onerel, NoLock); relation_close(onerel, NoLock);
CommitTransactionCommand(); CommitTransactionCommand();
return; return;
} }
...@@ -353,7 +369,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -353,7 +369,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
* before we commit. (If someone did, they'd fail to clean up the * before we commit. (If someone did, they'd fail to clean up the
* entries we made in pg_statistic.) * entries we made in pg_statistic.)
*/ */
heap_close(onerel, NoLock); relation_close(onerel, NoLock);
/* Commit and release working memory */ /* Commit and release working memory */
CommitTransactionCommand(); CommitTransactionCommand();
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -27,6 +27,7 @@
#include "access/xlog.h" #include "access/xlog.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/namespace.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_index.h" #include "catalog/pg_index.h"
#include "commands/vacuum.h" #include "commands/vacuum.h"
...@@ -40,19 +41,12 @@ ...@@ -40,19 +41,12 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/relcache.h" #include "utils/relcache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "pgstat.h" #include "pgstat.h"
typedef struct VRelListData
{
Oid vrl_relid;
struct VRelListData *vrl_next;
} VRelListData;
typedef VRelListData *VRelList;
typedef struct VacPageData typedef struct VacPageData
{ {
BlockNumber blkno; /* BlockNumber of this Page */ BlockNumber blkno; /* BlockNumber of this Page */
...@@ -118,13 +112,13 @@ static TransactionId initialFreezeLimit; ...@@ -118,13 +112,13 @@ static TransactionId initialFreezeLimit;
/* non-export function prototypes */ /* non-export function prototypes */
static void vacuum_init(VacuumStmt *vacstmt); static void vacuum_init(VacuumStmt *vacstmt);
static void vacuum_shutdown(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, static void vac_update_dbstats(Oid dbid,
TransactionId vacuumXID, TransactionId vacuumXID,
TransactionId frozenXID); TransactionId frozenXID);
static void vac_truncate_clog(TransactionId vacuumXID, static void vac_truncate_clog(TransactionId vacuumXID,
TransactionId frozenXID); 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 full_vacuum_rel(Relation onerel, VacuumStmt *vacstmt);
static void scan_heap(VRelStats *vacrelstats, Relation onerel, static void scan_heap(VRelStats *vacrelstats, Relation onerel,
VacPageList vacuum_pages, VacPageList fraged_pages); VacPageList vacuum_pages, VacPageList fraged_pages);
...@@ -167,10 +161,13 @@ void ...@@ -167,10 +161,13 @@ void
vacuum(VacuumStmt *vacstmt) vacuum(VacuumStmt *vacstmt)
{ {
const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE"; const char *stmttype = vacstmt->vacuum ? "VACUUM" : "ANALYZE";
NameData VacRel; List *vrl,
Name VacRelName; *cur;
VRelList vrl,
cur; if (vacstmt->verbose)
elevel = INFO;
else
elevel = DEBUG1;
/* /*
* We cannot run VACUUM inside a user transaction block; if we were * We cannot run VACUUM inside a user transaction block; if we were
...@@ -189,11 +186,6 @@ vacuum(VacuumStmt *vacstmt) ...@@ -189,11 +186,6 @@ vacuum(VacuumStmt *vacstmt)
*/ */
pgstat_vacuum_tabstat(); pgstat_vacuum_tabstat();
if (vacstmt->verbose)
elevel = INFO;
else
elevel = DEBUG1;
/* /*
* Create special memory context for cross-transaction storage. * Create special memory context for cross-transaction storage.
* *
...@@ -207,17 +199,8 @@ vacuum(VacuumStmt *vacstmt) ...@@ -207,17 +199,8 @@ vacuum(VacuumStmt *vacstmt)
ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE); 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) */ /* 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. * Start up the vacuum cleaner.
...@@ -231,12 +214,14 @@ vacuum(VacuumStmt *vacstmt) ...@@ -231,12 +214,14 @@ vacuum(VacuumStmt *vacstmt)
* ANALYZE part runs as a separate transaction from the VACUUM to * ANALYZE part runs as a separate transaction from the VACUUM to
* further reduce locking. * further reduce locking.
*/ */
for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next) foreach(cur, vrl)
{ {
Oid relid = (Oid) lfirsti(cur);
if (vacstmt->vacuum) if (vacstmt->vacuum)
vacuum_rel(cur->vrl_relid, vacstmt); vacuum_rel(relid, vacstmt, RELKIND_RELATION);
if (vacstmt->analyze) if (vacstmt->analyze)
analyze_rel(cur->vrl_relid, vacstmt); analyze_rel(relid, vacstmt);
} }
/* clean up */ /* clean up */
...@@ -323,85 +308,57 @@ vacuum_shutdown(VacuumStmt *vacstmt) ...@@ -323,85 +308,57 @@ 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 * The list is built in vac_context so that it will survive across our
* per-relation transactions. * per-relation transactions.
*/ */
static VRelList static List *
getrels(Name VacRelP, const char *stmttype) getrels(const RangeVar *vacrel, const char *stmttype)
{ {
Relation rel; List *vrl = NIL;
TupleDesc tupdesc; MemoryContext oldcontext;
HeapScanDesc scan;
HeapTuple tuple;
VRelList vrl,
cur;
Datum d;
char *rname;
char rkind;
bool n;
ScanKeyData key;
if (VacRelP) if (vacrel)
{ {
/* /* Process specific relation */
* we could use the cache here, but it is clearer to use scankeys Oid relid;
* for both vacuum cases, bjm 2000/01/19
*/ relid = RangeVarGetRelid(vacrel, false);
ScanKeyEntryInitialize(&key, 0x0, Anum_pg_class_relname,
F_NAMEEQ, /* Make a relation list entry for this guy */
PointerGetDatum(NameStr(*VacRelP))); oldcontext = MemoryContextSwitchTo(vac_context);
vrl = lappendi(vrl, relid);
MemoryContextSwitchTo(oldcontext);
} }
else else
{ {
/* find all plain relations listed in pg_class */ /* Process all plain relations listed in pg_class */
ScanKeyEntryInitialize(&key, 0x0, Anum_pg_class_relkind, Relation pgclass;
F_CHAREQ, CharGetDatum(RELKIND_RELATION)); 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); pgclass = heap_openr(RelationRelationName, AccessShareLock);
tupdesc = RelationGetDescr(rel);
scan = heap_beginscan(rel, false, SnapshotNow, 1, &key); scan = heap_beginscan(pgclass, false, SnapshotNow, 1, &key);
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) 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)
{
elog(WARNING, "%s: can not process indexes, views or special system tables",
stmttype);
continue;
}
/* Make a relation list entry for this guy */ /* Make a relation list entry for this guy */
if (vrl == (VRelList) NULL) oldcontext = MemoryContextSwitchTo(vac_context);
vrl = cur = (VRelList) vrl = lappendi(vrl, tuple->t_data->t_oid);
MemoryContextAlloc(vac_context, sizeof(VRelListData)); MemoryContextSwitchTo(oldcontext);
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_endscan(scan);
heap_close(rel, AccessShareLock); heap_close(pgclass, AccessShareLock);
}
if (vrl == NULL)
elog(WARNING, "%s: table not found", stmttype);
return vrl; return vrl;
} }
...@@ -663,7 +620,7 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID) ...@@ -663,7 +620,7 @@ vac_truncate_clog(TransactionId vacuumXID, TransactionId frozenXID)
* At entry and exit, we are not inside a transaction. * At entry and exit, we are not inside a transaction.
*/ */
static void static void
vacuum_rel(Oid relid, VacuumStmt *vacstmt) vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind)
{ {
LOCKMODE lmode; LOCKMODE lmode;
Relation onerel; Relation onerel;
...@@ -710,14 +667,27 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -710,14 +667,27 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
* Note we choose to treat permissions failure as a WARNING and keep * Note we choose to treat permissions failure as a WARNING and keep
* trying to vacuum the rest of the DB --- is this appropriate? * 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()) || if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) ||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared))) (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
{ {
elog(WARNING, "Skipping \"%s\" --- only table or database owner can VACUUM it", elog(WARNING, "Skipping \"%s\" --- only table or database owner can VACUUM it",
RelationGetRelationName(onerel)); 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(); CommitTransactionCommand();
return; return;
} }
...@@ -749,7 +719,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -749,7 +719,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
lazy_vacuum_rel(onerel, vacstmt); lazy_vacuum_rel(onerel, vacstmt);
/* all done with this class, but hold lock until commit */ /* 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. * Complete the transaction and free all temporary memory used.
...@@ -764,7 +734,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt) ...@@ -764,7 +734,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt)
* statistics are totally unimportant for toast relations. * statistics are totally unimportant for toast relations.
*/ */
if (toast_relid != InvalidOid) 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. * Now release the session-level lock on the master table.
...@@ -954,7 +924,9 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, ...@@ -954,7 +924,9 @@ scan_heap(VRelStats *vacrelstats, Relation onerel,
vac_init_rusage(&ru0); vac_init_rusage(&ru0);
relname = RelationGetRelationName(onerel); 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; empty_pages = new_pages = changed_pages = empty_end_pages = 0;
num_tuples = tups_vacuumed = nkeep = nunused = 0; num_tuples = tups_vacuumed = nkeep = nunused = 0;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -45,6 +45,7 @@
#include "storage/freespace.h" #include "storage/freespace.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/lsyscache.h"
/* /*
...@@ -207,7 +208,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -207,7 +208,9 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
vac_init_rusage(&ru0); vac_init_rusage(&ru0);
relname = RelationGetRelationName(onerel); relname = RelationGetRelationName(onerel);
elog(elevel, "--Relation %s--", relname); elog(elevel, "--Relation %s.%s--",
get_namespace_name(RelationGetNamespace(onerel)),
relname);
empty_pages = changed_pages = 0; empty_pages = changed_pages = 0;
num_tuples = tups_vacuumed = nkeep = nunused = 0; num_tuples = tups_vacuumed = nkeep = nunused = 0;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group * Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
* Copyright 1999 Jan Wieck * 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 @@ ...@@ -33,11 +33,10 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/spi_priv.h" #include "executor/spi_priv.h"
#include "nodes/makefuncs.h" #include "utils/lsyscache.h"
#include "miscadmin.h" #include "miscadmin.h"
...@@ -2954,18 +2953,7 @@ quoteOneName(char *buffer, const char *name) ...@@ -2954,18 +2953,7 @@ quoteOneName(char *buffer, const char *name)
static void static void
quoteRelationName(char *buffer, Relation rel) quoteRelationName(char *buffer, Relation rel)
{ {
HeapTuple tuple; quoteOneName(buffer, get_namespace_name(RelationGetNamespace(rel)));
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);
buffer += strlen(buffer); buffer += strlen(buffer);
*buffer++ = '.'; *buffer++ = '.';
quoteOneName(buffer, RelationGetRelationName(rel)); quoteOneName(buffer, RelationGetRelationName(rel));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "access/tupmacs.h" #include "access/tupmacs.h"
#include "catalog/pg_amop.h" #include "catalog/pg_amop.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
...@@ -1279,6 +1280,35 @@ free_attstatsslot(Oid atttype, ...@@ -1279,6 +1280,35 @@ free_attstatsslot(Oid atttype,
pfree(numbers); 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 ---------- */ /* ---------- PG_SHADOW CACHE ---------- */
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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, ...@@ -59,6 +59,7 @@ extern bool get_attstatsslot(HeapTuple statstuple,
extern void free_attstatsslot(Oid atttype, extern void free_attstatsslot(Oid atttype,
Datum *values, int nvalues, Datum *values, int nvalues,
float4 *numbers, int nnumbers); float4 *numbers, int nnumbers);
extern char *get_namespace_name(Oid nspid);
extern int32 get_usesysid(const char *username); extern int32 get_usesysid(const char *username);
#define TypeIsToastable(typid) (get_typstorage(typid) != 'p') #define TypeIsToastable(typid) (get_typstorage(typid) != 'p')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment