⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 catalog.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
字号:
/*------------------------------------------------------------------------- * * catalog.c *		routines concerned with catalog naming conventions * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.64 2005/10/15 02:49:12 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <fcntl.h>#include <unistd.h>#include "access/genam.h"#include "access/transam.h"#include "catalog/catalog.h"#include "catalog/pg_namespace.h"#include "catalog/pg_tablespace.h"#include "miscadmin.h"#include "storage/fd.h"#include "utils/fmgroids.h"#include "utils/relcache.h"#define OIDCHARS	10			/* max chars printed by %u *//* * relpath			- construct path to a relation's file * * Result is a palloc'd string. */char *relpath(RelFileNode rnode){	int			pathlen;	char	   *path;	if (rnode.spcNode == GLOBALTABLESPACE_OID)	{		/* Shared system relations live in {datadir}/global */		Assert(rnode.dbNode == 0);		pathlen = 7 + OIDCHARS + 1;		path = (char *) palloc(pathlen);		snprintf(path, pathlen, "global/%u",				 rnode.relNode);	}	else if (rnode.spcNode == DEFAULTTABLESPACE_OID)	{		/* The default tablespace is {datadir}/base */		pathlen = 5 + OIDCHARS + 1 + OIDCHARS + 1;		path = (char *) palloc(pathlen);		snprintf(path, pathlen, "base/%u/%u",				 rnode.dbNode, rnode.relNode);	}	else	{		/* All other tablespaces are accessed via symlinks */		pathlen = 10 + OIDCHARS + 1 + OIDCHARS + 1 + OIDCHARS + 1;		path = (char *) palloc(pathlen);		snprintf(path, pathlen, "pg_tblspc/%u/%u/%u",				 rnode.spcNode, rnode.dbNode, rnode.relNode);	}	return path;}/* * GetDatabasePath			- construct path to a database dir * * Result is a palloc'd string. * * XXX this must agree with relpath()! */char *GetDatabasePath(Oid dbNode, Oid spcNode){	int			pathlen;	char	   *path;	if (spcNode == GLOBALTABLESPACE_OID)	{		/* Shared system relations live in {datadir}/global */		Assert(dbNode == 0);		pathlen = 6 + 1;		path = (char *) palloc(pathlen);		snprintf(path, pathlen, "global");	}	else if (spcNode == DEFAULTTABLESPACE_OID)	{		/* The default tablespace is {datadir}/base */		pathlen = 5 + OIDCHARS + 1;		path = (char *) palloc(pathlen);		snprintf(path, pathlen, "base/%u",				 dbNode);	}	else	{		/* All other tablespaces are accessed via symlinks */		pathlen = 10 + OIDCHARS + 1 + OIDCHARS + 1;		path = (char *) palloc(pathlen);		snprintf(path, pathlen, "pg_tblspc/%u/%u",				 spcNode, dbNode);	}	return path;}/* * IsSystemRelation *		True iff the relation is a system catalog relation. * *		NB: TOAST relations are considered system relations by this test *		for compatibility with the old IsSystemRelationName function. *		This is appropriate in many places but not all.  Where it's not, *		also check IsToastRelation. * *		We now just test if the relation is in the system catalog namespace; *		so it's no longer necessary to forbid user relations from having *		names starting with pg_. */boolIsSystemRelation(Relation relation){	return IsSystemNamespace(RelationGetNamespace(relation)) ||		IsToastNamespace(RelationGetNamespace(relation));}/* * IsSystemClass *		Like the above, but takes a Form_pg_class as argument. *		Used when we do not want to open the relation and have to *		search pg_class directly. */boolIsSystemClass(Form_pg_class reltuple){	Oid			relnamespace = reltuple->relnamespace;	return IsSystemNamespace(relnamespace) ||		IsToastNamespace(relnamespace);}/* * IsToastRelation *		True iff relation is a TOAST support relation (or index). */boolIsToastRelation(Relation relation){	return IsToastNamespace(RelationGetNamespace(relation));}/* * IsToastClass *		Like the above, but takes a Form_pg_class as argument. *		Used when we do not want to open the relation and have to *		search pg_class directly. */boolIsToastClass(Form_pg_class reltuple){	Oid			relnamespace = reltuple->relnamespace;	return IsToastNamespace(relnamespace);}/* * IsSystemNamespace *		True iff namespace is pg_catalog. * * NOTE: the reason this isn't a macro is to avoid having to include * catalog/pg_namespace.h in a lot of places. */boolIsSystemNamespace(Oid namespaceId){	return namespaceId == PG_CATALOG_NAMESPACE;}/* * IsToastNamespace *		True iff namespace is pg_toast. * * NOTE: the reason this isn't a macro is to avoid having to include * catalog/pg_namespace.h in a lot of places. */boolIsToastNamespace(Oid namespaceId){	return namespaceId == PG_TOAST_NAMESPACE;}/* * IsReservedName *		True iff name starts with the pg_ prefix. * *		For some classes of objects, the prefix pg_ is reserved for *		system objects only.  As of 8.0, this is only true for *		schema and tablespace names. */boolIsReservedName(const char *name){	/* ugly coding for speed */	return (name[0] == 'p' &&			name[1] == 'g' &&			name[2] == '_');}/* * GetNewOid *		Generate a new OID that is unique within the given relation. * * Caller must have a suitable lock on the relation. * * Uniqueness is promised only if the relation has a unique index on OID. * This is true for all system catalogs that have OIDs, but might not be * true for user tables.  Note that we are effectively assuming that the * table has a relatively small number of entries (much less than 2^32) * and there aren't very long runs of consecutive existing OIDs.  Again, * this is reasonable for system catalogs but less so for user tables. * * Since the OID is not immediately inserted into the table, there is a * race condition here; but a problem could occur only if someone else * managed to cycle through 2^32 OIDs and generate the same OID before we * finish inserting our row.  This seems unlikely to be a problem.	Note * that if we had to *commit* the row to end the race condition, the risk * would be rather higher; therefore we use SnapshotDirty in the test, * so that we will see uncommitted rows. */OidGetNewOid(Relation relation){	Oid			newOid;	Oid			oidIndex;	Relation	indexrel;	/* If relation doesn't have OIDs at all, caller is confused */	Assert(relation->rd_rel->relhasoids);	/* In bootstrap mode, we don't have any indexes to use */	if (IsBootstrapProcessingMode())		return GetNewObjectId();	/* The relcache will cache the identity of the OID index for us */	oidIndex = RelationGetOidIndex(relation);	/* If no OID index, just hand back the next OID counter value */	if (!OidIsValid(oidIndex))	{		/*		 * System catalogs that have OIDs should *always* have a unique OID		 * index; we should only take this path for user tables. Give a		 * warning if it looks like somebody forgot an index.		 */		if (IsSystemRelation(relation))			elog(WARNING, "generating possibly-non-unique OID for \"%s\"",				 RelationGetRelationName(relation));		return GetNewObjectId();	}	/* Otherwise, use the index to find a nonconflicting OID */	indexrel = index_open(oidIndex);	newOid = GetNewOidWithIndex(relation, indexrel);	index_close(indexrel);	return newOid;}/* * GetNewOidWithIndex *		Guts of GetNewOid: use the supplied index * * This is exported separately because there are cases where we want to use * an index that will not be recognized by RelationGetOidIndex: TOAST tables * and pg_largeobject have indexes that are usable, but have multiple columns * and are on ordinary columns rather than a true OID column.  This code * will work anyway, so long as the OID is the index's first column. * * Caller must have a suitable lock on the relation. */OidGetNewOidWithIndex(Relation relation, Relation indexrel){	Oid			newOid;	IndexScanDesc scan;	ScanKeyData key;	bool		collides;	/* Generate new OIDs until we find one not in the table */	do	{		newOid = GetNewObjectId();		ScanKeyInit(&key,					(AttrNumber) 1,					BTEqualStrategyNumber, F_OIDEQ,					ObjectIdGetDatum(newOid));		/* see notes above about using SnapshotDirty */		scan = index_beginscan(relation, indexrel, SnapshotDirty, 1, &key);		collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));		index_endscan(scan);	} while (collides);	return newOid;}/* * GetNewRelFileNode *		Generate a new relfilenode number that is unique within the given *		tablespace. * * If the relfilenode will also be used as the relation's OID, pass the * opened pg_class catalog, and this routine will guarantee that the result * is also an unused OID within pg_class.  If the result is to be used only * as a relfilenode for an existing relation, pass NULL for pg_class. * * As with GetNewOid, there is some theoretical risk of a race condition, * but it doesn't seem worth worrying about. * * Note: we don't support using this in bootstrap mode.  All relations * created by bootstrap have preassigned OIDs, so there's no need. */OidGetNewRelFileNode(Oid reltablespace, bool relisshared, Relation pg_class){	RelFileNode rnode;	char	   *rpath;	int			fd;	bool		collides;	/* This should match RelationInitPhysicalAddr */	rnode.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace;	rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId;	do	{		/* Generate the OID */		if (pg_class)			rnode.relNode = GetNewOid(pg_class);		else			rnode.relNode = GetNewObjectId();		/* Check for existing file of same name */		rpath = relpath(rnode);		fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0);		if (fd >= 0)		{			/* definite collision */			close(fd);			collides = true;		}		else		{			/*			 * Here we have a little bit of a dilemma: if errno is something			 * other than ENOENT, should we declare a collision and loop? In			 * particular one might think this advisable for, say, EPERM.			 * However there really shouldn't be any unreadable files in a			 * tablespace directory, and if the EPERM is actually complaining			 * that we can't read the directory itself, we'd be in an infinite			 * loop.  In practice it seems best to go ahead regardless of the			 * errno.  If there is a colliding file we will get an smgr			 * failure when we attempt to create the new relation file.			 */			collides = false;		}		pfree(rpath);	} while (collides);	return rnode.relNode;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -