blob: d4b1531fb20fdf6a8eab5af1eeb71fcab1a1ceaf [file] [log] [blame]
/*-------------------------------------------------------------------------
*
* catalog.c
* routines concerned with catalog naming conventions and other
* bits of hard-wired knowledge
*
*
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.68 2006/10/04 00:29:50 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/indexing.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_pltemplate.h"
#include "catalog/pg_resqueue.h"
#include "catalog/pg_shdepend.h"
#include "catalog/pg_shdescription.h"
#include "catalog/pg_filespace.h"
#include "catalog/pg_filespace_entry.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_resqueue.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_tidycat.h"
#include "catalog/gp_configuration.h"
#include "catalog/gp_configuration.h"
#include "catalog/gp_segment_config.h"
#include "catalog/gp_san_config.h"
#include "catalog/gp_verification_history.h"
#include "catalog/gp_master_mirroring.h"
#include "catalog/gp_persistent.h"
#include "catalog/gp_global_sequence.h"
#include "catalog/gp_version.h"
#include "catalog/toasting.h"
#include "catalog/gp_policy.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/fmgroids.h"
#include "utils/relcache.h"
#include "utils/lsyscache.h"
#include "cdb/cdbpersistenttablespace.h"
#include "cdb/cdbdispatchedtablespaceinfo.h"
#include "cdb/cdbvars.h"
#include "commands/dbcommands.h"
#define OIDCHARS 10 /* max chars printed by %u */
void GetFilespacePathPrefix(Oid tablespaceOid, char **pathPrefix)
{
char *path = NULL;
GetFilespacePathForTablespace(tablespaceOid, &path);
if (path == NULL)
elog(ERROR, "cannot get table space location for content 0 table space %u", tablespaceOid);
int len = strlen(path);
if (len < 1 || path[len - 1] == '/')
{
path[len - 1] = 0;
len -= 1;
}
*pathPrefix = path;
}
void GetFilespacePathForTablespace(
Oid tablespaceOid,
char **filespacePath)
{
RC4PersistentTablespaceGetFilespaces tablespaceGetFilespaces;
Oid filespaceOid;
/* All other tablespaces are accessed via filespace locations */
char *ret_path;
Assert(tablespaceOid != GLOBALTABLESPACE_OID);
Assert(tablespaceOid != DEFAULTTABLESPACE_OID);
if (Gp_role != GP_ROLE_EXECUTE || IsBootstrapProcessingMode())
{
/* Lookup filespace location from the persistent object layer. */
tablespaceGetFilespaces =
PersistentTablespace_TryGetFilespacePath(
tablespaceOid,
&ret_path,
&filespaceOid);
}
else
{
bool found;
DispatchedFilespace_GetPathForTablespace(tablespaceOid, &ret_path, &found);
if (!found)
tablespaceGetFilespaces = RC4PersistentTablespaceGetFilespaces_TablespaceNotFound;
else
tablespaceGetFilespaces = RC4PersistentTablespaceGetFilespaces_Ok;
}
switch (tablespaceGetFilespaces)
{
case RC4PersistentTablespaceGetFilespaces_TablespaceNotFound:
ereport(ERROR,
(errcode(ERRCODE_CDB_INTERNAL_ERROR),
errmsg("Unable to find entry for tablespace OID = %u when forming file-system path",
tablespaceOid)));
break;
case RC4PersistentTablespaceGetFilespaces_FilespaceNotFound:
ereport(ERROR,
(errcode(ERRCODE_CDB_INTERNAL_ERROR),
errmsg("Unable to find entry for filespace OID = %u when forming file-system path for tablespace OID = %u",
filespaceOid,
tablespaceOid)));
break;
case RC4PersistentTablespaceGetFilespaces_Ok:
// Go below and pass back the result.
break;
default:
elog(ERROR, "Unexpected tablespace filespace fetch result: %d",
tablespaceGetFilespaces);
}
Assert(ret_path != NULL);
*filespacePath = ret_path;
}
/*
* relpath - construct path to a relation's file
*
* Result is a palloc'd string.
*/
char *
relpath(RelFileNode rnode)
{
int pathlen;
char *path;
int snprintfResult;
if (rnode.spcNode == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(rnode.dbNode == 0);
pathlen = 7 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintfResult =
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);
snprintfResult =
snprintf(path, pathlen, "base/%u/%u",
rnode.dbNode, rnode.relNode);
}
else
{
char *primary_path;
/* All other tablespaces are accessed via filespace locations */
GetFilespacePathForTablespace(
rnode.spcNode,
&primary_path);
/*
* We should develop an interface for the above that doesn't
* require reallocating to a slightly larger size...
*/
pathlen = strlen(primary_path)+1+OIDCHARS+1+OIDCHARS+1+OIDCHARS+1;
path = (char *) palloc(pathlen);
snprintfResult =
snprintf(path, pathlen, "%s/%u/%u/%u",
primary_path, rnode.spcNode, rnode.dbNode, rnode.relNode);
/* Throw away the allocation we got from persistent layer */
pfree(primary_path);
}
Assert(snprintfResult >= 0);
Assert(snprintfResult < pathlen);
return path;
}
void
CopyRelPath(char *target, int targetMaxLen, RelFileNode rnode)
{
int snprintfResult;
if (rnode.spcNode == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(rnode.dbNode == 0);
snprintfResult =
snprintf(target, targetMaxLen, "global/%u",
rnode.relNode);
}
else if (rnode.spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
snprintfResult =
snprintf(target, targetMaxLen, "base/%u/%u",
rnode.dbNode, rnode.relNode);
}
else
{
char *primary_path;
/* All other tablespaces are accessed via filespace locations */
GetFilespacePathForTablespace(
rnode.spcNode,
&primary_path);
/* Copy path into the passed in target location */
snprintfResult =
snprintf(target, targetMaxLen, "%s/%u/%u/%u",
primary_path, rnode.spcNode, rnode.dbNode, rnode.relNode);
/* Throw away the allocation we got from persistent layer */
pfree(primary_path);
}
if (snprintfResult < 0)
elog(ERROR, "CopyRelPath formatting error");
/*
* Magically truncating the result to fit in the target string is unacceptable here
* because it can result in the wrong file-system object being referenced.
*/
if (snprintfResult >= targetMaxLen)
elog(ERROR, "CopyRelPath formatting result length %d exceeded the maximum length %d",
snprintfResult,
targetMaxLen);
}
/*
* 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;
int snprintfResult;
if (spcNode == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(dbNode == 0);
pathlen = 6 + 1;
path = (char *) palloc(pathlen);
// Using strncpy is error prone.
snprintfResult =
snprintf(path, pathlen, "global");
}
else if (spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
pathlen = 5 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintfResult =
snprintf(path, pathlen, "base/%u",
dbNode);
}
else
{
char *primary_path;
/* All other tablespaces are accessed via filespace locations */
GetFilespacePathForTablespace(
spcNode,
&primary_path);
/*
* We should develop an interface for the above that doesn't
* require reallocating to a slightly larger size...
*/
pathlen = strlen(primary_path)+1+OIDCHARS+1+OIDCHARS+1;
path = (char *) palloc(pathlen);
snprintfResult =
snprintf(path, pathlen, "%s/%u/%u",
primary_path, spcNode, dbNode);
/* Throw away the allocation we got from persistent layer */
pfree(primary_path);
}
Assert(snprintfResult >= 0);
Assert(snprintfResult < pathlen);
return path;
}
void
CopyDatabasePath(char *target, int targetMaxLen, Oid dbNode, Oid spcNode)
{
int snprintfResult;
if (spcNode == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(dbNode == 0);
// Using strncpy is error prone.
snprintfResult =
snprintf(target, targetMaxLen, "global");
}
else if (spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
snprintfResult =
snprintf(target, targetMaxLen, "base/%u",
dbNode);
}
else
{
char *primary_path;
/* All other tablespaces are accessed via filespace locations */
GetFilespacePathForTablespace(
spcNode,
&primary_path);
/* Copy path into the passed in target location */
snprintfResult =
snprintf(target, targetMaxLen, "%s/%u/%u",
primary_path, spcNode, dbNode);
/* Throw away the allocation we got from persistent layer */
pfree(primary_path);
}
if (snprintfResult < 0)
elog(ERROR, "CopyDatabasePath formatting error");
/*
* Magically truncating the result to fit in the target string is unacceptable here
* because it can result in the wrong file-system object being referenced.
*/
if (snprintfResult >= targetMaxLen)
elog(ERROR, "CopyDatabasePath formatting result length %d exceeded the maximum length %d",
snprintfResult,
targetMaxLen);
}
void FormDatabasePath(
char *databasePath,
char *filespaceLocation,
Oid tablespaceOid,
Oid databaseOid)
{
int targetMaxLen = MAXPGPATH + 1;
int snprintfResult;
if (tablespaceOid == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(databaseOid == 0);
Assert(filespaceLocation == NULL);
// Using strncpy is error prone.
snprintfResult =
snprintf(databasePath, targetMaxLen, "global");
}
else if (tablespaceOid == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
Assert(filespaceLocation == NULL);
snprintfResult =
snprintf(databasePath, targetMaxLen, "base/%u",
databaseOid);
}
else
{
/* All other tablespaces are in filespace locations */
Assert(filespaceLocation != NULL);
snprintfResult =
snprintf(databasePath, targetMaxLen, "%s/%u/%u",
filespaceLocation, tablespaceOid, databaseOid);
}
if (snprintfResult < 0)
elog(ERROR, "CopyDatabasePath formatting error");
/*
* Magically truncating the result to fit in the target string is unacceptable here
* because it can result in the wrong file-system object being referenced.
*/
if (snprintfResult >= targetMaxLen)
elog(ERROR, "CopyDatabasePath formatting result length %d exceeded the maximum length %d",
snprintfResult,
targetMaxLen);
}
void FormTablespacePath(
char *tablespacePath,
char *filespaceLocation,
Oid tablespaceOid)
{
int targetMaxLen = MAXPGPATH + 1;
int snprintfResult;
if (tablespaceOid == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(filespaceLocation == NULL);
// Using strncpy is error prone.
snprintfResult =
snprintf(tablespacePath, targetMaxLen, "global");
}
else if (tablespaceOid == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
Assert(filespaceLocation == NULL);
// Using strncpy is error prone.
snprintfResult =
snprintf(tablespacePath, targetMaxLen, "base");
}
else
{
/* All other tablespaces are in filespace locations */
Assert(filespaceLocation != NULL);
snprintfResult =
snprintf(tablespacePath, targetMaxLen, "%s/%u",
filespaceLocation, tablespaceOid);
}
if (snprintfResult < 0)
elog(ERROR, "FormTablespacePath formatting error");
/*
* Magically truncating the result to fit in the target string is unacceptable here
* because it can result in the wrong file-system object being referenced.
*/
if (snprintfResult >= targetMaxLen)
elog(ERROR, "FormTablespacePath formatting result length %d exceeded the maximum length %d",
snprintfResult,
targetMaxLen);
}
void
FormRelationPath(char *relationPath, char *filespaceLocation, RelFileNode rnode)
{
int targetMaxLen = MAXPGPATH + 1;
int snprintfResult;
if (rnode.spcNode == GLOBALTABLESPACE_OID)
{
/* Shared system relations live in {datadir}/global */
Assert(rnode.dbNode == 0);
snprintfResult =
snprintf(relationPath, targetMaxLen, "global/%u",
rnode.relNode);
}
else if (rnode.spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
snprintfResult =
snprintf(relationPath, targetMaxLen, "base/%u/%u",
rnode.dbNode, rnode.relNode);
}
else
{
snprintfResult =
snprintf(relationPath, targetMaxLen, "%s/%u/%u/%u",
filespaceLocation,
rnode.spcNode,
rnode.dbNode,
rnode.relNode);
}
if (snprintfResult < 0)
elog(ERROR, "FormRelationPath formatting error");
/*
* Magically truncating the result to fit in the target string is unacceptable here
* because it can result in the wrong file-system object being referenced.
*/
if (snprintfResult >= targetMaxLen)
elog(ERROR, "FormRelationPath formatting result length %d exceeded the maximum length %d",
snprintfResult,
targetMaxLen);
}
/**
* Form path for relfile, it support not only catalog relfile but also relfile on hdfs
*/
void
FormRelfilePath(char *relfilePath, char *filespaceLocation, RelFileNode *rnode, int32 segmentFileNum)
{
char dbPath[MAXPGPATH + 1];
int targetMaxLen = MAXPGPATH + 1;
int snprintfResult;
FormDatabasePath(dbPath,
filespaceLocation,
rnode->spcNode,
rnode->dbNode);
if (IsLocalPath(dbPath))
{
/* catalog relfile rule same as postgres: all relfile at same level */
if (segmentFileNum == 0)
snprintfResult =
snprintf(relfilePath, targetMaxLen, "%s/%u", dbPath, rnode->relNode);
else
snprintfResult =
snprintf(relfilePath, targetMaxLen, "%s/%u.%u", dbPath, rnode->relNode, segmentFileNum);
}else
{
/* hdfs relfile rule change from file to directory at relation level, and segnum */
snprintfResult =
snprintf(relfilePath, targetMaxLen, "%s/%u/%u", dbPath, rnode->relNode, segmentFileNum);
}
if (snprintfResult < 0)
elog(ERROR, "FormRelfilePath formatting error");
/*
* Magically truncating the result to fit in the target string is unacceptable here
* because it can result in the wrong file-system object being referenced.
*/
if (snprintfResult >= targetMaxLen)
elog(ERROR, "FormRelfilePath formatting result length %d exceeded the maximum length %d",
snprintfResult,
targetMaxLen);
}
/*
* 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_.
*/
bool
IsSystemRelation(Relation relation)
{
return IsSystemNamespace(RelationGetNamespace(relation)) ||
IsToastNamespace(RelationGetNamespace(relation)) ||
IsAoSegmentNamespace(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.
*/
bool
IsSystemClass(Form_pg_class reltuple)
{
Oid relnamespace = reltuple->relnamespace;
return IsSystemNamespace(relnamespace) ||
IsToastNamespace(relnamespace) ||
IsAoSegmentNamespace(relnamespace);
}
/*
* IsToastRelation
* True iff relation is a TOAST support relation (or index).
*/
bool
IsToastRelation(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.
*/
bool
IsToastClass(Form_pg_class reltuple)
{
Oid relnamespace = reltuple->relnamespace;
return IsToastNamespace(relnamespace);
}
/*
* IsAoSegmentRelation
* True iff relation is an AO segment support relation (or index).
*/
bool
IsAoSegmentRelation(Relation relation)
{
return IsAoSegmentNamespace(RelationGetNamespace(relation));
}
/*
* IsAoSegmentClass
* 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.
*/
bool
IsAoSegmentClass(Form_pg_class reltuple)
{
Oid relnamespace = reltuple->relnamespace;
return IsAoSegmentNamespace(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.
*/
bool
IsSystemNamespace(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.
*/
bool
IsToastNamespace(Oid namespaceId)
{
return namespaceId == PG_TOAST_NAMESPACE;
}
/*
* IsAoSegmentNamespace
* True iff namespace is pg_aoseg.
*
* NOTE: the reason this isn't a macro is to avoid having to include
* catalog/pg_namespace.h in a lot of places.
*/
bool
IsAoSegmentNamespace(Oid namespaceId)
{
return namespaceId == PG_AOSEGMENT_NAMESPACE;
}
/**
* Method determines if a relation is master-only or distributed among segments.
* Input:
* relationOid
* Output:
* true if masteronly
*/
bool
isMasterOnly(Oid relationOid)
{
Assert(relationOid != InvalidOid);
Oid schemaOid = get_rel_namespace(relationOid);
GpPolicy *distributionPolicy = GpPolicyFetch(CurrentMemoryContext, relationOid);
bool masterOnly = (Gp_role == GP_ROLE_UTILITY
|| IsSystemNamespace(schemaOid)
|| IsToastNamespace(schemaOid)
|| IsAoSegmentNamespace(schemaOid)
|| (distributionPolicy == NULL)
|| (distributionPolicy->ptype == POLICYTYPE_ENTRY));
return masterOnly;
}
/*
* 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.
*
* As of Greenplum 4.0 we also reserve the prefix gp_
*/
bool
IsReservedName(const char *name)
{
/* ugly coding for speed */
return ((name[0] == 'p' && name[1] == 'g' && name[2] == '_') ||
(name[0] == 'g' && name[1] == 'p' && name[2] == '_'));
}
/*
* GetReservedPrefix
* Given a string that is a reserved name return the portion of
* the name that makes it reserved - the reserved prefix.
*
* Current return values include "pg_" and "gp_"
*/
char *
GetReservedPrefix(const char *name)
{
char *prefix = NULL;
if (IsReservedName(name))
{
prefix = palloc(4);
memcpy(prefix, name, 3);
prefix[3] = '\0';
}
return prefix;
}
/*
* IsSharedRelation
* Given the OID of a relation, determine whether it's supposed to be
* shared across an entire database cluster.
*
* Hard-wiring this list is pretty grotty, but we really need it so that
* we can compute the locktag for a relation (and then lock it) without
* having already read its pg_class entry. If we try to retrieve relisshared
* from pg_class with no pre-existing lock, there is a race condition against
* anyone who is concurrently committing a change to the pg_class entry:
* since we read system catalog entries under SnapshotNow, it's possible
* that both the old and new versions of the row are invalid at the instants
* we scan them. We fix this by insisting that updaters of a pg_class
* row must hold exclusive lock on the corresponding rel, and that users
* of a relation must hold at least AccessShareLock on the rel *before*
* trying to open its relcache entry. But to lock a rel, you have to
* know if it's shared. Fortunately, the set of shared relations is
* fairly static, so a hand-maintained list of their OIDs isn't completely
* impractical.
*/
bool
IsSharedRelation(Oid relationId)
{
/* These are the shared catalogs (look for BKI_SHARED_RELATION) */
if (
relationId == AuthMemRelationId ||
relationId == DatabaseRelationId ||
relationId == PLTemplateRelationId ||
relationId == SharedDescriptionRelationId ||
relationId == SharedDependRelationId ||
relationId == FileSpaceRelationId ||
relationId == TableSpaceRelationId ||
relationId == GpVersionRelationId ||
relationId == GpPersistentRelfileNodeRelationId ||
relationId == GpPersistentRelationNodeRelationId ||
relationId == GpPersistentDatabaseNodeRelationId ||
relationId == GpPersistentTablespaceNodeRelationId ||
relationId == GpPersistentFilespaceNodeRelationId ||
relationId == GpGlobalSequenceRelationId ||
/* MPP-6929: metadata tracking */
relationId == StatLastShOpRelationId ||
/* TIDYCAT_BEGIN_CODEGEN
*/
/*
WARNING: DO NOT MODIFY THE FOLLOWING SECTION:
Generated by ./tidycat.pl version 29
on Mon Aug 1 17:08:37 2011
*/
/* relation id: 1260 - pg_authid 20100129 */
relationId == AuthIdRelationId ||
/* relation id: 5008 - gp_master_mirroring 20101104 */
relationId == GpMasterMirroringRelationId ||
/* relation id: 5035 - gp_san_configuration 20101104 */
relationId == GpSanConfigRelationId ||
/* relation id: 5000 - gp_configuration 20101104 */
relationId == GpConfigurationRelationId ||
/* relation id: 5006 - gp_configuration_history 20101104 */
relationId == GpConfigHistoryRelationId ||
/* relation id: 5029 - gp_db_interfaces 20101104 */
relationId == GpDbInterfacesRelationId ||
/* relation id: 5030 - gp_interfaces 20101104 */
relationId == GpInterfacesRelationId ||
/* relation id: 5033 - pg_filespace_entry 20101122 */
relationId == FileSpaceEntryRelationId ||
/* relation id: 6429 - gp_verification_history 20110609 */
relationId == GpVerificationHistoryRelationId ||
/* relation id: 2914 - pg_auth_time_constraint 20110908 */
relationId == AuthTimeConstraintRelationId ||
/* relation id: 6112 - pg_filesystem 20130123 */
relationId == FileSystemRelationId ||
/* relation id: 5036 - gp_segment_configuration 20150204 */
relationId == GpSegmentConfigRelationId ||
/* relation id: 6026 - pg_resqueue 20151014 */
relationId == ResQueueRelationId ||
/* TIDYCAT_END_CODEGEN */
0 /* OR ZERO */
)
return true;
/* These are their indexes (see indexing.h) */
if (
relationId == AuthMemRoleMemIndexId ||
relationId == AuthMemMemRoleIndexId ||
relationId == DatabaseNameIndexId ||
relationId == DatabaseOidIndexId ||
relationId == PLTemplateNameIndexId ||
relationId == SharedDescriptionObjIndexId ||
relationId == SharedDependDependerIndexId ||
relationId == SharedDependReferenceIndexId ||
relationId == FilespaceOidIndexId ||
relationId == FilespaceNameIndexId ||
relationId == TablespaceOidIndexId ||
relationId == TablespaceNameIndexId ||
/* MPP-6929: metadata tracking */
relationId == StatLastShOpClassidObjidIndexId ||
relationId == StatLastShOpClassidObjidStaactionnameIndexId ||
/* TIDYCAT_BEGIN_CODEGEN
*/
/*
WARNING: DO NOT MODIFY THE FOLLOWING SECTION:
Generated by ./tidycat.pl version 31
on Thu May 24 14:25:58 2012
*/
/* relation id: 1260 - pg_authid 20100129 */
relationId == AuthIdRolnameIndexId ||
/* relation id: 1260 - pg_authid 20100129 */
relationId == AuthIdOidIndexId ||
/* relation id: 1260 - pg_authid 20100129 */
relationId == AuthIdRolResQueueIndexId ||
/* relation id: 5035 - gp_san_configuration 20101104 */
relationId == GpSanConfigMountidIndexId ||
/* relation id: 5000 - gp_configuration 20101104 */
relationId == GpConfigurationContentDefinedprimaryIndexId ||
/* relation id: 5000 - gp_configuration 20101104 */
relationId == GpConfigurationDbidIndexId ||
/* relation id: 5029 - gp_db_interfaces 20101104 */
relationId == GpDbInterfacesDbidIndexId ||
/* relation id: 5030 - gp_interfaces 20101104 */
relationId == GpInterfacesInterfaceidIndexId ||
/* relation id: 5033 - pg_filespace_entry 20101122 */
relationId == FileSpaceEntryFsefsoidIndexId ||
/* relation id: 5033 - pg_filespace_entry 20101122 */
relationId == FileSpaceEntryFsefsoidFsedbidIndexId ||
/* relation id: 6429 - gp_verification_history 20110609 */
relationId == GpVerificationHistoryVertokenIndexId ||
/* relation id: 6112 - pg_filesystem 20130123 */
relationId == FileSystemOidIndexId ||
/* relation id: 6112 - pg_filesystem 20130123 */
relationId == FileSystemFsysnameIndexId ||
/* relation id: 5036 - gp_segment_configuration 20150207 */
relationId == GpSegmentConfigRegistration_orderIndexId ||
/* relation id: 5036 - gp_segment_configuration 20150207 */
relationId == GpSegmentConfigRoleIndexId ||
/* relation id: 6026 - pg_resqueue 20151014 */
relationId == ResQueueOidIndexId ||
/* relation id: 6026 - pg_resqueue 20151014 */
relationId == ResQueueRsqnameIndexId ||
/* TIDYCAT_END_CODEGEN */
0 /* OR ZERO */
)
return true;
/* These are their toast tables and toast indexes (see toasting.h) */
if (relationId == PgAuthidToastTable ||
relationId == PgAuthidToastIndex ||
relationId == PgDatabaseToastTable ||
relationId == PgDatabaseToastIndex ||
relationId == PgShdescriptionToastTable ||
relationId == PgShdescriptionToastIndex ||
/* TIDYCAT_BEGIN_CODEGEN
*/
/* relation id: 5033 - pg_filespace_entry 20101122 */
relationId == PgFileSpaceEntryToastTable ||
relationId == PgFileSpaceEntryToastIndex ||
/* relation id: 6112 - pg_filesystem 20130123 */
relationId == PgFileSystemToastTable ||
relationId == PgFileSystemToastIndex ||
/* relation id: 5036 - gp_segment_configuration 20150204 */
relationId == GpSegmentConfigToastTable ||
relationId == GpSegmentConfigToastIndex ||
/* relation id: 6026 - pg_resqueue 20151014 */
relationId == PgResQueueToastTable ||
relationId == PgResQueueToastIndex ||
/* TIDYCAT_END_CODEGEN */
0 /* OR ZERO */
)
return true;
return false;
}
/*
* 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.
*/
Oid
GetNewOid(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))
{
Oid result;
/*
* 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));
result= GetNewObjectId();
if (IsSystemNamespace(RelationGetNamespace(relation)))
{
if (Gp_role == GP_ROLE_EXECUTE)
{
elog(DEBUG1,"Allocating Oid %u on relid %u %s in EXECUTE mode",result,relation->rd_id,RelationGetRelationName(relation));
}
if (Gp_role == GP_ROLE_DISPATCH)
{
elog(DEBUG5,"Allocating Oid %u on relid %u %s in DISPATCH mode",result,relation->rd_id,RelationGetRelationName(relation));
}
}
return result;
}
/* Otherwise, use the index to find a nonconflicting OID */
indexrel = index_open(oidIndex, AccessShareLock);
newOid = GetNewOidWithIndex(relation, indexrel);
index_close(indexrel, AccessShareLock);
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.
*/
Oid
GetNewOidWithIndex(Relation relation, Relation indexrel)
{
Oid newOid;
IndexScanDesc scan;
ScanKeyData key;
bool collides;
/* Generate new OIDs until we find one not in the table */
do
{
CHECK_FOR_INTERRUPTS();
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);
if (IsSystemNamespace(RelationGetNamespace(relation)))
{
if (Gp_role == GP_ROLE_EXECUTE)
{
if (relation->rd_id != 2604 /* pg_attrdef */ && relation->rd_id != 2606 /* pg_constraint */ && relation->rd_id != 2615 /* pg_namespace */)
elog(DEBUG1,"Allocating Oid %u with index on relid %u %s in EXECUTE mode",newOid,relation->rd_id, RelationGetRelationName(relation));
else
elog(DEBUG4,"Allocating Oid %u with index on relid %u %s in EXECUTE mode",newOid,relation->rd_id, RelationGetRelationName(relation));
}
if (Gp_role == GP_ROLE_DISPATCH)
{
elog(DEBUG5,"Allocating Oid %u with index on relid %u %s in DISPATCH mode",newOid,relation->rd_id, RelationGetRelationName(relation));
}
}
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.
*/
Oid
GetNewRelFileNode(Oid reltablespace, bool relisshared, Relation pg_class, bool isAo)
{
RelFileNode rnode;
char *rpath;
bool exist = false;
/* This should match RelationInitPhysicalAddr */
if (isAo && reltablespace == InvalidOid)
rnode.spcNode = get_database_dts(MyDatabaseId);
else if (isAo)
rnode.spcNode = reltablespace;
else
rnode.spcNode = MyDatabaseTableSpace;
rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId;
do
{
CHECK_FOR_INTERRUPTS();
/* 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);
exist = PathExist(rpath);
pfree(rpath);
} while (exist);
if (!gp_upgrade_mode && Gp_role == GP_ROLE_EXECUTE)
Insist(!PointerIsValid(pg_class));
elog(DEBUG1, "Calling GetNewRelFileNode in %s mode %s pg_class. "
"New relOid = %d",
(Gp_role == GP_ROLE_EXECUTE ? "execute" :
Gp_role == GP_ROLE_UTILITY ? "utility" :
"dispatch"), pg_class ? "with" : "without",
rnode.relNode );
return rnode.relNode;
}
bool
CheckNewRelFileNodeIsOk(Oid newOid, Oid reltablespace, bool relisshared,
Relation pg_class, bool isAo)
{
RelFileNode rnode;
char *rpath;
int fd;
bool collides;
if (pg_class)
{
Oid oidIndex;
Relation indexrel;
IndexScanDesc scan;
ScanKeyData key;
Assert(!IsBootstrapProcessingMode());
Assert(pg_class->rd_rel->relhasoids);
/* The relcache will cache the identity of the OID index for us */
oidIndex = RelationGetOidIndex(pg_class);
Assert(OidIsValid(oidIndex));
indexrel = index_open(oidIndex, AccessShareLock);
ScanKeyInit(&key,
(AttrNumber) 1,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(newOid));
scan = index_beginscan(pg_class, indexrel, SnapshotDirty, 1, &key);
collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection));
index_endscan(scan);
index_close(indexrel, AccessShareLock);
if (collides)
elog(ERROR, "relfilenode %d already in use in \"pg_class\"",
newOid);
}
/* This should match RelationInitPhysicalAddr */
if (isAo && reltablespace == InvalidOid)
rnode.spcNode = get_database_dts(MyDatabaseId);
else if (isAo)
rnode.spcNode = reltablespace;
else
rnode.spcNode = MyDatabaseTableSpace;
rnode.dbNode = relisshared ? InvalidOid : MyDatabaseId;
rnode.relNode = newOid;
/* Check for existing file of same name */
rpath = relpath(rnode);
fd = BasicOpenFile(rpath, O_RDONLY | PG_BINARY, 0);
if (fd >= 0)
{
/* definite collision */
gp_retry_close(fd);
collides = true;
}
else
collides = false;
pfree(rpath);
if (collides && !relisshared)
elog(ERROR, "oid %d already in use", newOid);
while(GetNewObjectId() < newOid);
return !collides;
}