📄 heap.c
字号:
/*------------------------------------------------------------------------- * * heap.c * code to create and destroy POSTGRES heap relations * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/heap.c,v 1.89 1999/07/08 02:46:37 momjian Exp $ * * * INTERFACE ROUTINES * heap_create() - Create an uncataloged heap relation * heap_create_with_catalog() - Create a cataloged relation * heap_destroy_with_catalog() - Removes named relation from catalogs * * NOTES * this code taken from access/heap/create.c, which contains * the old heap_create_with_catalog, amcreate, and amdestroy. * those routines will soon call these routines using the function * manager, * just like the poorly named "NewXXX" routines do. The * "New" routines are all going to die soon, once and for all! * -cim 1/13/91 * *------------------------------------------------------------------------- */#include "postgres.h"#include "miscadmin.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/catname.h"#include "catalog/heap.h"#include "catalog/index.h"#include "catalog/indexing.h"#include "catalog/pg_attrdef.h"#include "catalog/pg_index.h"#include "catalog/pg_inherits.h"#include "catalog/pg_ipl.h"#include "catalog/pg_relcheck.h"#include "catalog/pg_type.h"#include "commands/trigger.h"#include "fmgr.h"#include "nodes/plannodes.h"#include "optimizer/tlist.h"#include "parser/parse_expr.h"#include "parser/parse_node.h"#include "parser/parse_target.h"#include "parser/parse_type.h"#include "parser/parse_coerce.h"#include "rewrite/rewriteRemove.h"#include "storage/bufmgr.h"#include "storage/lmgr.h"#include "storage/smgr.h"#include "tcop/tcopprot.h"#include "utils/catcache.h"#include "utils/builtins.h"#include "utils/mcxt.h"#include "utils/relcache.h"#include "utils/syscache.h"#include "utils/tqual.h"#include "utils/temprel.h"#ifndef HAVE_MEMMOVE#include <regex/utils.h>#else#include <string.h>#endifstatic void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, unsigned natts, char relkind, char *temp_relname);static void AddToNoNameRelList(Relation r);static void DeleteAttributeTuples(Relation rel);static void DeleteRelationTuple(Relation rel);static void DeleteTypeTuple(Relation rel);static void RelationRemoveIndexes(Relation relation);static void RelationRemoveInheritance(Relation relation);static void RemoveFromNoNameRelList(Relation r);static void AddNewRelationType(char *typeName, Oid new_rel_oid);static void StoreConstraints(Relation rel);static void RemoveConstraints(Relation rel);/* ---------------------------------------------------------------- * XXX UGLY HARD CODED BADNESS FOLLOWS XXX * * these should all be moved to someplace in the lib/catalog * module, if not obliterated first. * ---------------------------------------------------------------- *//* * Note: * Should the executor special case these attributes in the future? * Advantage: consume 1/2 the space in the ATTRIBUTE relation. * Disadvantage: having rules to compute values in these tuples may * be more difficult if not impossible. */static FormData_pg_attribute a1 = { 0xffffffff, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData), SelfItemPointerAttributeNumber, 0, -1, -1, '\0', '\0', 'i', '\0', '\0'};static FormData_pg_attribute a2 = { 0xffffffff, {"oid"}, OIDOID, 0, sizeof(Oid), ObjectIdAttributeNumber, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'};static FormData_pg_attribute a3 = { 0xffffffff, {"xmin"}, XIDOID, 0, sizeof(TransactionId), MinTransactionIdAttributeNumber, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'};static FormData_pg_attribute a4 = { 0xffffffff, {"cmin"}, CIDOID, 0, sizeof(CommandId), MinCommandIdAttributeNumber, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'};static FormData_pg_attribute a5 = { 0xffffffff, {"xmax"}, XIDOID, 0, sizeof(TransactionId), MaxTransactionIdAttributeNumber, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'};static FormData_pg_attribute a6 = { 0xffffffff, {"cmax"}, CIDOID, 0, sizeof(CommandId), MaxCommandIdAttributeNumber, 0, -1, -1, '\001', '\0', 'i', '\0', '\0'};static Form_pg_attribute HeapAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6};/* ---------------------------------------------------------------- * XXX END OF UGLY HARD CODED BADNESS XXX * ---------------------------------------------------------------- *//* the tempRelList holds the list of temporary uncatalogued relations that are created. these relations should be destroyed at the end of transactions*/typedef struct tempRelList{ Relation *rels; /* array of relation descriptors */ int num; /* number of temporary relations */ int size; /* size of space allocated for the rels * array */} TempRelList;#define NONAME_REL_LIST_SIZE 32static TempRelList *tempRels = NULL;/* ---------------------------------------------------------------- * heap_create - Create an uncataloged heap relation * * Fields relpages, reltuples, reltuples, relkeys, relhistory, * relisindexed, and relkind of rel->rd_rel are initialized * to all zeros, as are rd_last and rd_hook. Rd_refcnt is set to 1. * * Remove the system relation specific code to elsewhere eventually. * * Eventually, must place information about this temporary relation * into the transaction context block. * * * if heap_create is called with "" as the name, then heap_create will create * a temporary name "pg_noname.$PID.$SEQUENCE" for the relation * ---------------------------------------------------------------- */Relationheap_create(char *relname, TupleDesc tupDesc, bool isnoname, bool istemp){ unsigned i; Oid relid; Relation rel; int len; bool nailme = false; int natts = tupDesc->natts; static unsigned int uniqueId = 0; extern GlobalMemory CacheCxt; MemoryContext oldcxt; /* ---------------- * sanity checks * ---------------- */ AssertArg(natts > 0); if (relname && !allowSystemTableMods && IsSystemRelationName(relname) && IsNormalProcessingMode()) { elog(ERROR, "Illegal class name '%s'" "\n\tThe 'pg_' name prefix is reserved for system catalogs", relname); } /* ---------------- * switch to the cache context so that we don't lose * allocations at the end of this transaction, I guess. * -cim 6/14/90 * ---------------- */ if (!CacheCxt) CacheCxt = CreateGlobalMemory("Cache"); oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt); /* ---------------- * real ugly stuff to assign the proper relid in the relation * descriptor follows. * ---------------- */ if (relname && !strcmp(RelationRelationName, relname)) { relid = RelOid_pg_class; nailme = true; } else if (relname && !strcmp(AttributeRelationName, relname)) { relid = RelOid_pg_attribute; nailme = true; } else if (relname && !strcmp(ProcedureRelationName, relname)) { relid = RelOid_pg_proc; nailme = true; } else if (relname && !strcmp(TypeRelationName, relname)) { relid = RelOid_pg_type; nailme = true; } else relid = newoid(); if (isnoname) { Assert(!relname); relname = palloc(NAMEDATALEN); snprintf(relname, NAMEDATALEN, "pg_noname.%d.%u", (int) MyProcPid, uniqueId++); } if (istemp) { /* replace relname of caller */ snprintf(relname, NAMEDATALEN, "pg_temp.%d.%u", MyProcPid, uniqueId++); } /* ---------------- * allocate a new relation descriptor. * * XXX the length computation may be incorrect, handle elsewhere * ---------------- */ len = sizeof(RelationData); rel = (Relation) palloc(len); MemSet((char *) rel, 0, len); /* * create a new tuple descriptor from the one passed in */ rel->rd_att = CreateTupleDescCopyConstr(tupDesc); /* ---------------- * nail the reldesc if this is a bootstrap create reln and * we may need it in the cache later on in the bootstrap * process so we don't ever want it kicked out. e.g. pg_attribute!!! * ---------------- */ if (nailme) rel->rd_isnailed = true; RelationSetReferenceCount(rel, 1); rel->rd_rel = (Form_pg_class) palloc(sizeof *rel->rd_rel); /* ---------------- * initialize the fields of our new relation descriptor * ---------------- */ MemSet((char *) rel->rd_rel, 0, sizeof *rel->rd_rel); namestrcpy(&(rel->rd_rel->relname), relname); rel->rd_rel->relkind = RELKIND_UNCATALOGED; rel->rd_rel->relnatts = natts; if (tupDesc->constr) rel->rd_rel->relchecks = tupDesc->constr->num_check; for (i = 0; i < natts; i++) rel->rd_att->attrs[i]->attrelid = relid; RelationGetRelid(rel) = relid; if (nailme) { /* for system relations, set the reltype field here */ rel->rd_rel->reltype = relid; } /* ---------------- * remember if this is a noname relation * ---------------- */ rel->rd_isnoname = isnoname; /* ---------------- * have the storage manager create the relation. * ---------------- */ rel->rd_nonameunlinked = TRUE; /* change once table is created */ rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel); rel->rd_nonameunlinked = FALSE; RelationRegisterRelation(rel); MemoryContextSwitchTo(oldcxt); /* * add all noname relations to the tempRels list so they can be * properly disposed of at the end of transaction */ if (isnoname) AddToNoNameRelList(rel); return rel;}/* ---------------------------------------------------------------- * heap_create_with_catalog - Create a cataloged relation * * this is done in 6 steps: * * 1) CheckAttributeNames() is used to make certain the tuple * descriptor contains a valid set of attribute names * * 2) pg_class is opened and RelationFindRelid() * preforms a scan to ensure that no relation with the * same name already exists. * * 3) heap_create_with_catalog() is called to create the new relation * on disk. * * 4) TypeDefine() is called to define a new type corresponding * to the new relation. * * 5) AddNewAttributeTuples() is called to register the * new relation's schema in pg_attribute. * * 6) AddNewRelationTuple() is called to register the * relation itself in the catalogs. * * 7) StoreConstraints is called () - vadim 08/22/97 * * 8) the relations are closed and the new relation's oid * is returned. * * old comments: * A new relation is inserted into the RELATION relation * with the specified attribute(s) (newly inserted into * the ATTRIBUTE relation). How does concurrency control * work? Is it automatic now? Expects the caller to have * attname, atttypid, atttyparg, attproc, and attlen domains filled. * Create fills the attnum domains sequentually from zero, * fills the attdisbursion domains with zeros, and fills the * attrelid fields with the relid. * * scan relation catalog for name conflict * scan type catalog for typids (if not arg) * create and insert attribute(s) into attribute catalog * create new relation * insert new relation into attribute catalog * * Should coordinate with heap_create_with_catalog(). Either * it should not be called or there should be a way to prevent * the relation from being removed at the end of the * transaction if it is successful ('u'/'r' may be enough). * Also, if the transaction does not commit, then the * relation should be removed. * * XXX amcreate ignores "off" when inserting (for now). * XXX amcreate (like the other utilities) needs to understand indexes. * * ---------------------------------------------------------------- *//* -------------------------------- * CheckAttributeNames * * this is used to make certain the tuple descriptor contains a * valid set of attribute names. a problem simply generates * elog(ERROR) which aborts the current transaction. * -------------------------------- */static voidCheckAttributeNames(TupleDesc tupdesc){ unsigned i; unsigned j; int natts = tupdesc->natts; /* ---------------- * first check for collision with system attribute names * ---------------- * * also, warn user if attribute to be created has * an unknown typid (usually as a result of a 'retrieve into' * - jolly */ for (i = 0; i < natts; i += 1) { for (j = 0; j < sizeof HeapAtt / sizeof HeapAtt[0]; j += 1) { if (nameeq(&(HeapAtt[j]->attname), &(tupdesc->attrs[i]->attname))) { elog(ERROR, "Attribute '%s' has a name conflict" "\n\tName matches an existing system attribute", HeapAtt[j]->attname.data); } } if (tupdesc->attrs[i]->atttypid == UNKNOWNOID) { elog(NOTICE, "Attribute '%s' has an unknown type" "\n\tRelation created; continue", tupdesc->attrs[i]->attname.data); } } /* ---------------- * next check for repeated attribute names * ---------------- */ for (i = 1; i < natts; i += 1) { for (j = 0; j < i; j += 1) { if (nameeq(&(tupdesc->attrs[j]->attname), &(tupdesc->attrs[i]->attname))) { elog(ERROR, "Attribute '%s' is repeated", tupdesc->attrs[j]->attname.data); } } }}/* -------------------------------- * RelnameFindRelid * * this preforms a scan of pg_class to ensure that * no relation with the same name already exists. * -------------------------------- */OidRelnameFindRelid(char *relname){ HeapTuple tuple; Oid relid; /* * If this is not bootstrap (initdb) time, use the catalog index on * pg_class. */ if (!IsBootstrapProcessingMode()) { tuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname), 0, 0, 0); if (HeapTupleIsValid(tuple)) relid = tuple->t_data->t_oid; else relid = InvalidOid; } else { Relation pg_class_desc; ScanKeyData key; HeapScanDesc pg_class_scan; pg_class_desc = heap_openr(RelationRelationName); /* ---------------- * At bootstrap time, we have to do this the hard way. Form the * scan key. * ---------------- */ ScanKeyEntryInitialize(&key, 0, (AttrNumber) Anum_pg_class_relname, (RegProcedure) F_NAMEEQ, (Datum) relname); /* ---------------- * begin the scan * ---------------- */ pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key); /* ---------------- * get a tuple. if the tuple is NULL then it means we * didn't find an existing relation. * ---------------- */ tuple = heap_getnext(pg_class_scan, 0); if (HeapTupleIsValid(tuple)) relid = tuple->t_data->t_oid; else relid = InvalidOid; heap_endscan(pg_class_scan); heap_close(pg_class_desc); } return relid;}/* -------------------------------- * AddNewAttributeTuples * * this registers the new relation's schema by adding * tuples to pg_attribute. * -------------------------------- */static voidAddNewAttributeTuples(Oid new_rel_oid, TupleDesc tupdesc){ Form_pg_attribute *dpp; unsigned i; HeapTuple tup; Relation rel; bool hasindex; Relation idescs[Num_pg_attr_indices]; int natts = tupdesc->natts; /* ---------------- * open pg_attribute * ---------------- */ rel = heap_openr(AttributeRelationName); /* ----------------- * Check if we have any indices defined on pg_attribute. * ----------------- */ Assert(rel); Assert(rel->rd_rel); hasindex = RelationGetForm(rel)->relhasindex; if (hasindex) CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs); /* ---------------- * initialize tuple descriptor. Note we use setheapoverride() * so that we can see the effects of our TypeDefine() done * previously. * ---------------- */ setheapoverride(true); fillatt(tupdesc); setheapoverride(false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -