📄 heap.c
字号:
/* ---------------- * first we add the user attributes.. * ---------------- */ dpp = tupdesc->attrs; for (i = 0; i < natts; i++) { (*dpp)->attrelid = new_rel_oid; (*dpp)->attdisbursion = 0; tup = heap_addheader(Natts_pg_attribute, ATTRIBUTE_TUPLE_SIZE, (char *) *dpp); heap_insert(rel, tup); if (hasindex) CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup); pfree(tup); dpp++; } /* ---------------- * next we add the system attributes.. * ---------------- */ dpp = HeapAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) { (*dpp)->attrelid = new_rel_oid; /* (*dpp)->attdisbursion = 0; unneeded */ tup = heap_addheader(Natts_pg_attribute, ATTRIBUTE_TUPLE_SIZE, (char *) *dpp); heap_insert(rel, tup); if (hasindex) CatalogIndexInsert(idescs, Num_pg_attr_indices, rel, tup); pfree(tup); dpp++; } heap_close(rel); /* * close pg_attribute indices */ if (hasindex) CatalogCloseIndices(Num_pg_attr_indices, idescs);}/* -------------------------------- * AddNewRelationTuple * * this registers the new relation in the catalogs by * adding a tuple to pg_class. * -------------------------------- */static voidAddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, unsigned natts, char relkind, char *temp_relname){ Form_pg_class new_rel_reltup; HeapTuple tup; Relation idescs[Num_pg_class_indices]; bool isBootstrap; /* ---------------- * first we munge some of the information in our * uncataloged relation's relation descriptor. * ---------------- */ new_rel_reltup = new_rel_desc->rd_rel; /* CHECK should get new_rel_oid first via an insert then use XXX */ /* ---------------- * Here we insert bogus estimates of the size of the new relation. * In reality, of course, the new relation has 0 tuples and pages, * and if we were tracking these statistics accurately then we'd * set the fields that way. But at present the stats will be updated * only by VACUUM or CREATE INDEX, and the user might insert a lot of * tuples before he gets around to doing either of those. So, instead * of saying the relation is empty, we insert guesstimates. The point * is to keep the optimizer from making really stupid choices on * never-yet-vacuumed tables; so the estimates need only be large * enough to discourage the optimizer from using nested-loop plans. * With this hack, nested-loop plans will be preferred only after * the table has been proven to be small by VACUUM or CREATE INDEX. * Maintaining the stats on-the-fly would solve the problem more cleanly, * but the overhead of that would likely cost more than it'd save. * (NOTE: CREATE INDEX inserts the same bogus estimates if it finds the * relation has 0 rows and pages. See index.c.) * ---------------- */ new_rel_reltup->relpages = 10; /* bogus estimates */ new_rel_reltup->reltuples = 1000; new_rel_reltup->relowner = GetUserId(); new_rel_reltup->relkind = relkind; new_rel_reltup->relnatts = natts; /* ---------------- * now form a tuple to add to pg_class * XXX Natts_pg_class_fixed is a hack - see pg_class.h * ---------------- */ tup = heap_addheader(Natts_pg_class_fixed, CLASS_TUPLE_SIZE, (char *) new_rel_reltup); tup->t_data->t_oid = new_rel_oid; /* ---------------- * finally insert the new tuple and free it. * * Note: I have no idea why we do a * SetProcessingMode(BootstrapProcessing); * here -cim 6/14/90 * ---------------- */ isBootstrap = IsBootstrapProcessingMode() ? true : false; SetProcessingMode(BootstrapProcessing); heap_insert(pg_class_desc, tup); if (temp_relname) create_temp_relation(temp_relname, tup); if (!isBootstrap) { /* * First, open the catalog indices and insert index tuples for the * new relation. */ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class_desc, tup); CatalogCloseIndices(Num_pg_class_indices, idescs); /* now restore processing mode */ SetProcessingMode(NormalProcessing); } pfree(tup);}/* -------------------------------- * AddNewRelationType - * * define a complex type corresponding to the new relation * -------------------------------- */static voidAddNewRelationType(char *typeName, Oid new_rel_oid){ Oid new_type_oid; /* * The sizes are set to oid size because it makes implementing sets * MUCH easier, and no one (we hope) uses these fields to figure out * how much space to allocate for the type. An oid is the type used * for a set definition. When a user requests a set, what they * actually get is the oid of a tuple in the pg_proc catalog, so the * size of the "set" is the size of an oid. Similarly, byval being * true makes sets much easier, and it isn't used by anything else. * Note the assumption that OIDs are the same size as int4s. */ new_type_oid = TypeCreate(typeName, /* type name */ new_rel_oid, /* relation oid */ typeLen(typeidType(OIDOID)), /* internal size */ typeLen(typeidType(OIDOID)), /* external size */ 'c', /* type-type (catalog) */ ',', /* default array delimiter */ "int4in", /* input procedure */ "int4out", /* output procedure */ "int4in", /* receive procedure */ "int4out", /* send procedure */ NULL, /* array element type - irrelevent */ "-", /* default type value */ (bool) 1, /* passed by value */ 'i'); /* default alignment */}/* -------------------------------- * heap_create_with_catalog * * creates a new cataloged relation. see comments above. * -------------------------------- */Oidheap_create_with_catalog(char *relname, TupleDesc tupdesc, char relkind, bool istemp){ Relation pg_class_desc; Relation new_rel_desc; Oid new_rel_oid; int natts = tupdesc->natts; char *temp_relname = NULL; /* ---------------- * sanity checks * ---------------- */ Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode()); if (natts == 0 || natts > MaxHeapAttributeNumber) elog(ERROR, "Number of attributes is out of range" "\n\tFrom 1 to %d attributes may be specified", MaxHeapAttributeNumber); CheckAttributeNames(tupdesc); /* temp tables can mask non-temp tables */ if ((!istemp && RelnameFindRelid(relname)) || (istemp && get_temp_rel_by_name(relname) != NULL)) elog(ERROR, "Relation '%s' already exists", relname); /* invalidate cache so non-temp table is masked by temp */ if (istemp) { Oid relid = RelnameFindRelid(relname); if (relid != InvalidOid) RelationForgetRelation(relid); } /* save user relation name because heap_create changes it */ if (istemp) { temp_relname = pstrdup(relname); /* save original value */ relname = palloc(NAMEDATALEN); strcpy(relname, temp_relname); /* heap_create will change this */ } /* ---------------- * ok, relation does not already exist so now we * create an uncataloged relation and pull its relation oid * from the newly formed relation descriptor. * * Note: The call to heap_create() does all the "real" work * of creating the disk file for the relation. * This changes relname for noname and temp tables. * ---------------- */ new_rel_desc = heap_create(relname, tupdesc, false, istemp); new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid; /* ---------------- * since defining a relation also defines a complex type, * we add a new system type corresponding to the new relation. * ---------------- */ AddNewRelationType(relname, new_rel_oid); /* ---------------- * now add tuples to pg_attribute for the attributes in * our new relation. * ---------------- */ AddNewAttributeTuples(new_rel_oid, tupdesc); /* ---------------- * now update the information in pg_class. * ---------------- */ pg_class_desc = heap_openr(RelationRelationName); AddNewRelationTuple(pg_class_desc, new_rel_desc, new_rel_oid, natts, relkind, temp_relname); StoreConstraints(new_rel_desc); if (istemp) { pfree(relname); pfree(temp_relname); } /* ---------------- * ok, the relation has been cataloged, so close our relations * and return the oid of the newly created relation. * * SOMEDAY: fill the STATISTIC relation properly. * ---------------- */ heap_close(new_rel_desc); heap_close(pg_class_desc); return new_rel_oid;}/* ---------------------------------------------------------------- * heap_destroy_with_catalog - removes all record of named relation from catalogs * * 1) open relation, check for existence, etc. * 2) remove inheritance information * 3) remove indexes * 4) remove pg_class tuple * 5) remove pg_attribute tuples * 6) remove pg_type tuples * 7) RemoveConstraints () * 8) unlink relation * * old comments * Except for vital relations, removes relation from * relation catalog, and related attributes from * attribute catalog (needed?). (Anything else?) * * get proper relation from relation catalog (if not arg) * check if relation is vital (strcmp()/reltype?) * scan attribute catalog deleting attributes of reldesc * (necessary?) * delete relation from relation catalog * (How are the tuples of the relation discarded?) * * XXX Must fix to work with indexes. * There may be a better order for doing things. * Problems with destroying a deleted database--cannot create * a struct reldesc without having an open file descriptor. * ---------------------------------------------------------------- *//* -------------------------------- * RelationRemoveInheritance * * Note: for now, we cause an exception if relation is a * superclass. Someday, we may want to allow this and merge * the type info into subclass procedures.... this seems like * lots of work. * -------------------------------- */static voidRelationRemoveInheritance(Relation relation){ Relation catalogRelation; HeapTuple tuple; HeapScanDesc scan; ScanKeyData entry; bool found = false; /* ---------------- * open pg_inherits * ---------------- */ catalogRelation = heap_openr(InheritsRelationName); /* ---------------- * form a scan key for the subclasses of this class * and begin scanning * ---------------- */ ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_inherits_inhparent, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); scan = heap_beginscan(catalogRelation, false, SnapshotNow, 1, &entry); /* ---------------- * if any subclasses exist, then we disallow the deletion. * ---------------- */ tuple = heap_getnext(scan, 0); if (HeapTupleIsValid(tuple)) { heap_endscan(scan); heap_close(catalogRelation); elog(ERROR, "Relation '%u' inherits '%s'", ((Form_pg_inherits) GETSTRUCT(tuple))->inhrel, RelationGetRelationName(relation)); } /* ---------------- * If we get here, it means the relation has no subclasses * so we can trash it. First we remove dead INHERITS tuples. * ---------------- */ entry.sk_attno = Anum_pg_inherits_inhrel; scan = heap_beginscan(catalogRelation, false, SnapshotNow, 1, &entry); while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { heap_delete(catalogRelation, &tuple->t_self, NULL); found = true; } heap_endscan(scan); heap_close(catalogRelation); /* ---------------- * now remove dead IPL tuples * ---------------- */ catalogRelation = heap_openr(InheritancePrecidenceListRelationName); entry.sk_attno = Anum_pg_ipl_iplrel; scan = heap_beginscan(catalogRelation, false, SnapshotNow, 1, &entry); while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) heap_delete(catalogRelation, &tuple->t_self, NULL); heap_endscan(scan); heap_close(catalogRelation);}/* -------------------------------- * RelationRemoveIndexes * * -------------------------------- */static voidRelationRemoveIndexes(Relation relation){ Relation indexRelation; HeapTuple tuple; HeapScanDesc scan; ScanKeyData entry; indexRelation = heap_openr(IndexRelationName); ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_index_indrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry); while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) index_destroy(((Form_pg_index) GETSTRUCT(tuple))->indexrelid); heap_endscan(scan); heap_close(indexRelation);}/* -------------------------------- * DeleteRelationTuple * * -------------------------------- */static voidDeleteRelationTuple(Relation rel){ Relation pg_class_desc; HeapTuple tup; /* ---------------- * open pg_class * ---------------- */ pg_class_desc = heap_openr(RelationRelationName); tup = SearchSysCacheTupleCopy(RELOID, ObjectIdGetDatum(rel->rd_att->attrs[0]->attrelid), 0, 0, 0); if (!HeapTupleIsValid(tup)) { heap_close(pg_class_desc); elog(ERROR, "Relation '%s' does not exist", &rel->rd_rel->relname); } /* ---------------- * delete the relation tuple from pg_class, and finish up. * ---------------- */ heap_delete(pg_class_desc, &tup->t_self, NULL); pfree(tup); heap_close(pg_class_desc);}/* -------------------------------- * DeleteAttributeTuples * * -------------------------------- */static voidDeleteAttributeTuples(Relation rel){ Relation pg_attribute_desc; HeapTuple tup; int2 attnum; /* ---------------- * open pg_attribute * ---------------- */ pg_attribute_desc = heap_openr(AttributeRelationName); /* ----------------- * Get a write lock _before_ getting the read lock in the scan * ---------------- */ LockRelation(pg_attribute_desc, AccessExclusiveLock); for (attnum = FirstLowInvalidHeapAttributeNumber + 1; attnum <= rel->rd_att->natts; attnum++) { if (HeapTupleIsValid(tup = SearchSysCacheTupleCopy(ATTNUM, ObjectIdGetDatum(RelationGetRelid(rel)), Int16GetDatum(attnum), 0, 0))) { heap_delete(pg_attribute_desc, &tup->t_self, NULL); pfree(tup); } } /* ---------------- * Release the write lock * ---------------- */ UnlockRelation(pg_attribute_desc, AccessExclusiveLock); heap_close(pg_attribute_desc);}/* -------------------------------- * DeleteTypeTuple * * If the user attempts to destroy a relation and there * exists attributes in other relations of type * "relation we are deleting", then we have to do something * special. presently we disallow the destroy. * -------------------------------- */static voidDeleteTypeTuple(Relation rel){ Relation pg_type_desc; HeapScanDesc pg_type_scan; Relation pg_attribute_desc; HeapScanDesc pg_attribute_scan; ScanKeyData key; ScanKeyData attkey; HeapTuple tup; HeapTuple atttup; Oid typoid; /* ---------------- * open pg_type * ---------------- */ pg_type_desc = heap_openr(TypeRelationName);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -