#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
-#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
-#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_tablespace.h"
*/
#define RELCACHE_INIT_FILENAME "pg_internal.init"
-#define RELCACHE_INIT_FILEMAGIC 0x573265 /* version ID value */
+#define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */
/*
- * hardcoded tuple descriptors, generated by genbki.pl
+ * hardcoded tuple descriptors, contents generated by genbki.pl
*/
static const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
/*
* Special cache for opclass-related information
*
- * Note: only default operators and support procs get cached, ie, those with
+ * Note: only default support procs get cached, ie, those with
* lefttype = righttype = opcintype.
*/
typedef struct opclasscacheent
{
Oid opclassoid; /* lookup key: OID of opclass */
bool valid; /* set TRUE after successful fill-in */
- StrategyNumber numStrats; /* max # of strategies (from pg_am) */
StrategyNumber numSupport; /* max # of support procs (from pg_am) */
Oid opcfamily; /* OID of opclass's family */
Oid opcintype; /* OID of opclass's declared input type */
- Oid *operatorOids; /* strategy operators' OIDs */
- RegProcedure *supportProcs; /* support procs */
+ RegProcedure *supportProcs; /* OIDs of support procedures */
} OpClassCacheEnt;
static HTAB *OpClassCache = NULL;
static void CheckConstraintFetch(Relation relation);
static List *insert_ordered_oid(List *list, Oid datum);
static void IndexSupportInitialize(oidvector *indclass,
- Oid *indexOperator,
RegProcedure *indexSupport,
Oid *opFamily,
Oid *opcInType,
- StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber);
static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
- StrategyNumber numStrats,
StrategyNumber numSupport);
static void RelationCacheInitFileRemoveInDir(const char *tblspcpath);
static void unlink_initfile(const char *initfilename);
relation->rd_isnailed = false;
relation->rd_createSubid = InvalidSubTransactionId;
relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
- relation->rd_istemp = relation->rd_rel->relistemp;
- if (!relation->rd_istemp)
- relation->rd_backend = InvalidBackendId;
- else if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
- relation->rd_backend = MyBackendId;
- else
+ switch (relation->rd_rel->relpersistence)
{
- /*
- * If it's a temporary table, but not one of ours, we have to use
- * the slow, grotty method to figure out the owning backend.
- */
- relation->rd_backend =
- GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
- Assert(relation->rd_backend != InvalidBackendId);
+ case RELPERSISTENCE_PERMANENT:
+ relation->rd_backend = InvalidBackendId;
+ break;
+ case RELPERSISTENCE_TEMP:
+ if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
+ relation->rd_backend = MyBackendId;
+ else
+ {
+ /*
+ * If it's a local temp table, but not one of ours, we have to
+ * use the slow, grotty method to figure out the owning
+ * backend.
+ */
+ relation->rd_backend =
+ GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
+ Assert(relation->rd_backend != InvalidBackendId);
+ }
+ break;
+ default:
+ elog(ERROR, "invalid relpersistence: %c",
+ relation->rd_rel->relpersistence);
+ break;
}
/*
MemoryContext indexcxt;
MemoryContext oldcontext;
int natts;
- uint16 amstrategies;
uint16 amsupport;
/*
if (natts != relation->rd_index->indnatts)
elog(ERROR, "relnatts disagrees with indnatts for index %u",
RelationGetRelid(relation));
- amstrategies = aform->amstrategies;
amsupport = aform->amsupport;
/*
relation->rd_opcintype = (Oid *)
MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
- if (amstrategies > 0)
- relation->rd_operator = (Oid *)
- MemoryContextAllocZero(indexcxt,
- natts * amstrategies * sizeof(Oid));
- else
- relation->rd_operator = NULL;
-
if (amsupport > 0)
{
int nsupport = natts * amsupport;
indclass = (oidvector *) DatumGetPointer(indclassDatum);
/*
- * Fill the operator and support procedure OID arrays, as well as the info
- * about opfamilies and opclass input types. (aminfo and supportinfo are
- * left as zeroes, and are filled on-the-fly when used)
+ * Fill the support procedure OID array, as well as the info about
+ * opfamilies and opclass input types. (aminfo and supportinfo are left
+ * as zeroes, and are filled on-the-fly when used)
*/
- IndexSupportInitialize(indclass,
- relation->rd_operator, relation->rd_support,
+ IndexSupportInitialize(indclass, relation->rd_support,
relation->rd_opfamily, relation->rd_opcintype,
- amstrategies, amsupport, natts);
+ amsupport, natts);
/*
* Similarly extract indoption and copy it to the cache entry
* Initializes an index's cached opclass information,
* given the index's pg_index.indclass entry.
*
- * Data is returned into *indexOperator, *indexSupport, *opFamily, and
- * *opcInType, which are arrays allocated by the caller.
+ * Data is returned into *indexSupport, *opFamily, and *opcInType,
+ * which are arrays allocated by the caller.
*
- * The caller also passes maxStrategyNumber, maxSupportNumber, and
- * maxAttributeNumber, since these indicate the size of the arrays
- * it has allocated --- but in practice these numbers must always match
- * those obtainable from the system catalog entries for the index and
- * access method.
+ * The caller also passes maxSupportNumber and maxAttributeNumber, since these
+ * indicate the size of the arrays it has allocated --- but in practice these
+ * numbers must always match those obtainable from the system catalog entries
+ * for the index and access method.
*/
static void
IndexSupportInitialize(oidvector *indclass,
- Oid *indexOperator,
RegProcedure *indexSupport,
Oid *opFamily,
Oid *opcInType,
- StrategyNumber maxStrategyNumber,
StrategyNumber maxSupportNumber,
AttrNumber maxAttributeNumber)
{
/* look up the info for this opclass, using a cache */
opcentry = LookupOpclassInfo(indclass->values[attIndex],
- maxStrategyNumber,
maxSupportNumber);
/* copy cached data into relcache entry */
opFamily[attIndex] = opcentry->opcfamily;
opcInType[attIndex] = opcentry->opcintype;
- if (maxStrategyNumber > 0)
- memcpy(&indexOperator[attIndex * maxStrategyNumber],
- opcentry->operatorOids,
- maxStrategyNumber * sizeof(Oid));
if (maxSupportNumber > 0)
memcpy(&indexSupport[attIndex * maxSupportNumber],
opcentry->supportProcs,
* This routine maintains a per-opclass cache of the information needed
* by IndexSupportInitialize(). This is more efficient than relying on
* the catalog cache, because we can load all the info about a particular
- * opclass in a single indexscan of pg_amproc or pg_amop.
+ * opclass in a single indexscan of pg_amproc.
*
- * The information from pg_am about expected range of strategy and support
+ * The information from pg_am about expected range of support function
* numbers is passed in, rather than being looked up, mainly because the
* caller will have it already.
*
*/
static OpClassCacheEnt *
LookupOpclassInfo(Oid operatorClassOid,
- StrategyNumber numStrats,
StrategyNumber numSupport)
{
OpClassCacheEnt *opcentry;
{
/* Need to allocate memory for new entry */
opcentry->valid = false; /* until known OK */
- opcentry->numStrats = numStrats;
opcentry->numSupport = numSupport;
- if (numStrats > 0)
- opcentry->operatorOids = (Oid *)
- MemoryContextAllocZero(CacheMemoryContext,
- numStrats * sizeof(Oid));
- else
- opcentry->operatorOids = NULL;
-
if (numSupport > 0)
opcentry->supportProcs = (RegProcedure *)
MemoryContextAllocZero(CacheMemoryContext,
}
else
{
- Assert(numStrats == opcentry->numStrats);
Assert(numSupport == opcentry->numSupport);
}
/*
* We have to fetch the pg_opclass row to determine its opfamily and
- * opcintype, which are needed to look up the operators and functions.
+ * opcintype, which are needed to look up related operators and functions.
* It'd be convenient to use the syscache here, but that probably doesn't
* work while bootstrapping.
*/
systable_endscan(scan);
heap_close(rel, AccessShareLock);
-
- /*
- * Scan pg_amop to obtain operators for the opclass. We only fetch the
- * default ones (those with lefttype = righttype = opcintype).
- */
- if (numStrats > 0)
- {
- ScanKeyInit(&skey[0],
- Anum_pg_amop_amopfamily,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(opcentry->opcfamily));
- ScanKeyInit(&skey[1],
- Anum_pg_amop_amoplefttype,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(opcentry->opcintype));
- ScanKeyInit(&skey[2],
- Anum_pg_amop_amoprighttype,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(opcentry->opcintype));
- rel = heap_open(AccessMethodOperatorRelationId, AccessShareLock);
- scan = systable_beginscan(rel, AccessMethodStrategyIndexId, indexOK,
- SnapshotNow, 3, skey);
-
- while (HeapTupleIsValid(htup = systable_getnext(scan)))
- {
- Form_pg_amop amopform = (Form_pg_amop) GETSTRUCT(htup);
-
- if (amopform->amopstrategy <= 0 ||
- (StrategyNumber) amopform->amopstrategy > numStrats)
- elog(ERROR, "invalid amopstrategy number %d for opclass %u",
- amopform->amopstrategy, operatorClassOid);
- opcentry->operatorOids[amopform->amopstrategy - 1] =
- amopform->amopopr;
- }
-
- systable_endscan(scan);
- heap_close(rel, AccessShareLock);
- }
-
/*
* Scan pg_amproc to obtain support procs for the opclass. We only fetch
* the default ones (those with lefttype = righttype = opcintype).
relation->rd_isnailed = true;
relation->rd_createSubid = InvalidSubTransactionId;
relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
- relation->rd_istemp = false;
relation->rd_backend = InvalidBackendId;
/*
if (isshared)
relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
- /*
- * Likewise, we must know if a relation is temp ... but formrdesc is not
- * used for any temp relations.
- */
- relation->rd_rel->relistemp = false;
+ /* formrdesc is used only for permanent relations */
+ relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
relation->rd_rel->relpages = 1;
relation->rd_rel->reltuples = 1;
Oid relid,
Oid reltablespace,
bool shared_relation,
- bool mapped_relation)
+ bool mapped_relation,
+ char relpersistence)
{
Relation rel;
MemoryContext oldcxt;
/* must flag that we have rels created in this transaction */
need_eoxact_work = true;
- /* it is temporary if and only if it is in my temp-table namespace */
- rel->rd_istemp = isTempOrToastNamespace(relnamespace);
- rel->rd_backend = rel->rd_istemp ? MyBackendId : InvalidBackendId;
-
/*
* create a new tuple descriptor from the one passed in. We do this
* partly to copy it into the cache context, and partly because the new
/* needed when bootstrapping: */
rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
+ /* set up persistence; rd_backend is a function of persistence type */
+ rel->rd_rel->relpersistence = relpersistence;
+ switch (relpersistence)
+ {
+ case RELPERSISTENCE_PERMANENT:
+ rel->rd_backend = InvalidBackendId;
+ break;
+ case RELPERSISTENCE_TEMP:
+ rel->rd_backend = MyBackendId;
+ break;
+ default:
+ elog(ERROR, "invalid relpersistence: %c", relpersistence);
+ break;
+ }
+
/*
* Insert relation physical and logical identifiers (OIDs) into the right
* places. Note that the physical ID (relfilenode) is initially the same
* map.
*/
rel->rd_rel->relisshared = shared_relation;
- rel->rd_rel->relistemp = rel->rd_istemp;
RelationGetRelid(rel) = relid;
* Caller must already hold exclusive lock on the relation.
*
* The relation is marked with relfrozenxid = freezeXid (InvalidTransactionId
- * must be passed for indexes). This should be a lower bound on the XIDs
- * that will be put into the new relation contents.
+ * must be passed for indexes and sequences). This should be a lower bound on
+ * the XIDs that will be put into the new relation contents.
*/
void
RelationSetNewRelfilenode(Relation relation, TransactionId freezeXid)
HeapTuple tuple;
Form_pg_class classform;
- /* Indexes must have Invalid frozenxid; other relations must not */
- Assert((relation->rd_rel->relkind == RELKIND_INDEX &&
- freezeXid == InvalidTransactionId) ||
+ /* Indexes, sequences must have Invalid frozenxid; other rels must not */
+ Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
+ relation->rd_rel->relkind == RELKIND_SEQUENCE) ?
+ freezeXid == InvalidTransactionId :
TransactionIdIsNormal(freezeXid));
/* Allocate a new relfilenode */
newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
- relation->rd_backend);
+ relation->rd_rel->relpersistence);
/*
* Get a writable copy of the pg_class tuple for the given relation.
newrnode.node = relation->rd_node;
newrnode.node.relNode = newrelfilenode;
newrnode.backend = relation->rd_backend;
- RelationCreateStorage(newrnode.node, relation->rd_istemp);
+ RelationCreateStorage(newrnode.node, relation->rd_rel->relpersistence);
smgrclosenode(newrnode);
/*
classform->relfilenode = newrelfilenode;
/* These changes are safe even for a mapped relation */
- classform->relpages = 0; /* it's empty until further notice */
- classform->reltuples = 0;
+ if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
+ {
+ classform->relpages = 0; /* it's empty until further notice */
+ classform->reltuples = 0;
+ }
classform->relfrozenxid = freezeXid;
simple_heap_update(pg_class, &tuple->t_self, tuple);
&ctl, HASH_ELEM | HASH_FUNCTION);
/*
- * relation mapper needs initialized too
+ * relation mapper needs to be initialized too
*/
RelationMapInitialize();
}
IndexRelationId);
load_critical_index(OpclassOidIndexId,
OperatorClassRelationId);
- load_critical_index(AccessMethodStrategyIndexId,
- AccessMethodOperatorRelationId);
load_critical_index(AccessMethodProcedureIndexId,
AccessMethodProcedureRelationId);
- load_critical_index(OperatorOidIndexId,
- OperatorRelationId);
load_critical_index(RewriteRelRulenameIndexId,
RewriteRelationId);
load_critical_index(TriggerRelidNameIndexId,
TriggerRelationId);
-#define NUM_CRITICAL_LOCAL_INDEXES 9 /* fix if you change list above */
+#define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
criticalRelcachesBuilt = true;
}
MemoryContext indexcxt;
Oid *opfamily;
Oid *opcintype;
- Oid *operator;
RegProcedure *support;
int nsupport;
int16 *indoption;
rel->rd_opcintype = opcintype;
- /* next, read the vector of operator OIDs */
- if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
- goto read_failed;
-
- operator = (Oid *) MemoryContextAlloc(indexcxt, len);
- if (fread(operator, 1, len, fp) != len)
- goto read_failed;
-
- rel->rd_operator = operator;
-
- /* next, read the vector of support procedures */
+ /* next, read the vector of support procedure OIDs */
if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
goto read_failed;
support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
Assert(rel->rd_aminfo == NULL);
Assert(rel->rd_opfamily == NULL);
Assert(rel->rd_opcintype == NULL);
- Assert(rel->rd_operator == NULL);
Assert(rel->rd_support == NULL);
Assert(rel->rd_supportinfo == NULL);
Assert(rel->rd_indoption == NULL);
relform->relnatts * sizeof(Oid),
fp);
- /* next, write the vector of operator OIDs */
- write_item(rel->rd_operator,
- relform->relnatts * (am->amstrategies * sizeof(Oid)),
- fp);
-
- /* next, write the vector of support procedures */
+ /* next, write the vector of support procedure OIDs */
write_item(rel->rd_support,
relform->relnatts * (am->amsupport * sizeof(RegProcedure)),
fp);