heap.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,069 行 · 第 1/4 页
C
2,069 行
* pinned. */ if (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE) { dpp = SysAtt; for (i = 0; i < -1 - FirstLowInvalidHeapAttributeNumber; i++) { if (tupdesc->tdhasoid || (*dpp)->attnum != ObjectIdAttributeNumber) { Form_pg_attribute attStruct; tup = heap_addheader(Natts_pg_attribute, false, ATTRIBUTE_TUPLE_SIZE, (void *) *dpp); /* Fill in the correct relation OID in the copied tuple */ attStruct = (Form_pg_attribute) GETSTRUCT(tup); attStruct->attrelid = new_rel_oid; /* * Unneeded since they should be OK in the constant data * anyway */ /* attStruct->attstattarget = 0; */ /* attStruct->attcacheoff = -1; */ simple_heap_insert(rel, tup); CatalogIndexInsert(indstate, tup); heap_freetuple(tup); } dpp++; } } /* * clean up */ CatalogCloseIndexes(indstate); heap_close(rel, RowExclusiveLock);}/* -------------------------------- * 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, Oid new_type_oid, char relkind){ Form_pg_class new_rel_reltup; HeapTuple tup; /* * first we update some of the information in our uncataloged * relation's relation descriptor. */ new_rel_reltup = new_rel_desc->rd_rel; /* * 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.) */ switch (relkind) { case RELKIND_RELATION: case RELKIND_INDEX: case RELKIND_TOASTVALUE: new_rel_reltup->relpages = 10; /* bogus estimates */ new_rel_reltup->reltuples = 1000; break; case RELKIND_SEQUENCE: new_rel_reltup->relpages = 1; new_rel_reltup->reltuples = 1; break; default: /* views, etc */ new_rel_reltup->relpages = 0; new_rel_reltup->reltuples = 0; break; } new_rel_reltup->relowner = GetUserId(); new_rel_reltup->reltype = new_type_oid; new_rel_reltup->relkind = relkind; /* ---------------- * 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, true, CLASS_TUPLE_SIZE, (void *) new_rel_reltup); /* force tuple to have the desired OID */ HeapTupleSetOid(tup, new_rel_oid); /* * finally insert the new tuple, update the indexes, and clean up. */ simple_heap_insert(pg_class_desc, tup); CatalogUpdateIndexes(pg_class_desc, tup); heap_freetuple(tup);}/* -------------------------------- * AddNewRelationType - * * define a complex type corresponding to the new relation * -------------------------------- */static voidAddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind, Oid new_type_oid){ /* * We set the I/O procedures of a complex type to record_in and * record_out, so that a user will get an error message not a weird * number if he tries to SELECT a complex type. * * OLD and probably obsolete comments: * * 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. */ TypeCreate(typeName, /* type name */ typeNamespace, /* type namespace */ new_type_oid, /* preassigned oid for type */ new_rel_oid, /* relation oid */ new_rel_kind, /* relation kind */ sizeof(Oid), /* internal size */ 'c', /* type-type (complex) */ ',', /* default array delimiter */ F_RECORD_IN, /* input procedure */ F_RECORD_OUT, /* output procedure */ F_RECORD_RECV, /* receive procedure */ F_RECORD_SEND, /* send procedure */ InvalidOid, /* array element type - irrelevant */ InvalidOid, /* domain base type - irrelevant */ NULL, /* default type value - none */ NULL, /* default type binary representation */ true, /* passed by value */ 'i', /* default alignment - same as for OID */ 'p', /* Not TOASTable */ -1, /* typmod */ 0, /* array dimensions for typBaseType */ false); /* Type NOT NULL */}/* -------------------------------- * heap_create_with_catalog * * creates a new cataloged relation. see comments above. * -------------------------------- */Oidheap_create_with_catalog(const char *relname, Oid relnamespace, TupleDesc tupdesc, char relkind, bool shared_relation, OnCommitAction oncommit, bool allow_system_table_mods){ Relation pg_class_desc; Relation new_rel_desc; Oid new_rel_oid; Oid new_type_oid; /* * sanity checks */ Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode()); CheckAttributeNamesTypes(tupdesc, relkind); if (get_relname_relid(relname, relnamespace)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("relation \"%s\" already exists", relname))); /* * Create the relcache entry (mostly dummy at this point) and the * physical disk file. (If we fail further down, it's the smgr's * responsibility to remove the disk file again.) * * NB: create a physical file only if it's not a view or type relation. */ new_rel_desc = heap_create(relname, relnamespace, tupdesc, shared_relation, (relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE), allow_system_table_mods); /* Fetch the relation OID assigned by heap_create */ new_rel_oid = RelationGetRelid(new_rel_desc); /* Assign an OID for the relation's tuple type */ new_type_oid = newoid(); /* * now create an entry in pg_class for the relation. * * NOTE: we could get a unique-index failure here, in case someone else * is creating the same relation name in parallel but hadn't committed * yet when we checked for a duplicate name above. */ pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock); AddNewRelationTuple(pg_class_desc, new_rel_desc, new_rel_oid, new_type_oid, relkind); /* * since defining a relation also defines a complex type, we add a new * system type corresponding to the new relation. * * NOTE: we could get a unique-index failure here, in case the same name * has already been used for a type. */ AddNewRelationType(relname, relnamespace, new_rel_oid, relkind, new_type_oid); /* * now add tuples to pg_attribute for the attributes in our new * relation. */ AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relkind); /* * make a dependency link to force the relation to be deleted if its * namespace is. Skip this in bootstrap mode, since we don't make * dependencies while bootstrapping. */ if (!IsBootstrapProcessingMode()) { ObjectAddress myself, referenced; myself.classId = RelOid_pg_class; myself.objectId = new_rel_oid; myself.objectSubId = 0; referenced.classId = get_system_catalog_relid(NamespaceRelationName); referenced.objectId = relnamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } /* * store constraints and defaults passed in the tupdesc, if any. * * NB: this may do a CommandCounterIncrement and rebuild the relcache * entry, so the relation must be valid and self-consistent at this * point. In particular, there are not yet constraints and defaults * anywhere. */ StoreConstraints(new_rel_desc, tupdesc); /* * If there's a special on-commit action, remember it */ if (oncommit != ONCOMMIT_NOOP) register_on_commit_action(new_rel_oid, oncommit); /* * ok, the relation has been cataloged, so close our relations and * return the oid of the newly created relation. */ heap_close(new_rel_desc, NoLock); /* do not unlock till end of xact */ heap_close(pg_class_desc, RowExclusiveLock); return new_rel_oid;}/* * RelationRemoveInheritance * * Formerly, this routine checked for child relations and aborted the * deletion if any were found. Now we rely on the dependency mechanism * to check for or delete child relations. By the time we get here, * there are no children and we need only remove any pg_inherits rows * linking this relation to its parent(s). */static voidRelationRemoveInheritance(Relation relation){ Relation catalogRelation; SysScanDesc scan; ScanKeyData key; HeapTuple tuple; catalogRelation = heap_openr(InheritsRelationName, RowExclusiveLock); ScanKeyEntryInitialize(&key, 0x0, Anum_pg_inherits_inhrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndex, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(scan))) simple_heap_delete(catalogRelation, &tuple->t_self); systable_endscan(scan); heap_close(catalogRelation, RowExclusiveLock);}/* * DeleteRelationTuple * * Remove pg_class row for the given relid. * * Note: this is shared by relation deletion and index deletion. It's * not intended for use anyplace else. */voidDeleteRelationTuple(Oid relid){ Relation pg_class_desc; HeapTuple tup; /* Grab an appropriate lock on the pg_class relation */ pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock); tup = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0); if (!HeapTupleIsValid(tup)) elog(ERROR, "cache lookup failed for relation %u", relid); /* delete the relation tuple from pg_class, and finish up */ simple_heap_delete(pg_class_desc, &tup->t_self); ReleaseSysCache(tup); heap_close(pg_class_desc, RowExclusiveLock);}/* * DeleteAttributeTuples * * Remove pg_attribute rows for the given relid. * * Note: this is shared by relation deletion and index deletion. It's * not intended for use anyplace else. */voidDeleteAttributeTuples(Oid relid){ Relation attrel; SysScanDesc scan; ScanKeyData key[1]; HeapTuple atttup; /* Grab an appropriate lock on the pg_attribute relation */ attrel = heap_openr(AttributeRelationName, RowExclusiveLock); /* Use the index to scan only attributes of the target relation */ ScanKeyEntryInitialize(&key[0], 0x0, Anum_pg_attribute_attrelid, F_OIDEQ, ObjectIdGetDatum(relid)); scan = systable_beginscan(attrel, AttributeRelidNumIndex, true, SnapshotNow, 1, key); /* Delete all the matching tuples */ while ((atttup = systable_getnext(scan)) != NULL) simple_heap_delete(attrel, &atttup->t_self); /* Clean up after the scan */ systable_endscan(scan); heap_close(attrel, RowExclusiveLock);}/* * RemoveAttributeById * * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute * deleted in pg_attribute. We also remove pg_statistic entries for it. * (Everything else needed, such as getting rid of any pg_attrdef entry, * is handled by dependency.c.) */voidRemoveAttributeById(Oid relid, AttrNumber attnum){ Relation rel; Relation attr_rel; HeapTuple tuple; Form_pg_attribute attStruct; char newattname[NAMEDATALEN]; /* * Grab an exclusive lock on the target table, which we will NOT * release until end of transaction. (In the simple case where we are * directly dropping this column, AlterTableDropColumn already did * this ... but when cascading from a drop of some other object, we * may not have any lock.) */ rel = relation_open(relid, AccessExclusiveLock); attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock); tuple = SearchSysCacheCopy(ATTNUM, ObjectIdGetDatum(relid), Int16GetDatum(attnum), 0, 0); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, relid); attStruct = (Form_pg_attribute) GETSTRUCT(tuple); /* Mark the attribute as dropped */ attStruct->attisdropped = true; /* * Set the type OID to invalid. A dropped attribute's type link * cannot be relied on (once the attribute is dropped, the type might * be too). Fortunately we do not need the type row --- the only * really essential information is the type's typlen and typalign, * which are preserved in the attribute's attlen and attalign. We set * atttypid to zero here as a means of catching code that incorrectly * expects it to be valid. */ attStruct->atttypid = InvalidOid; /* Remove any NOT NULL constraint the column may have */ attStruct->attnotnull = false; /* We don't want to keep stats for it anymore */ attStruct->attstattarget = 0; /* Change the column name to something that isn't likely to conflict */ snprintf(newattname, sizeof(newattname), "........pg.dropped.%d........", attnum); namestrcpy(&(attStruct->attname), newattname); simple_heap_update(attr_rel, &tuple->t_self, tuple); /* keep the system catalog indexes current */ CatalogUpdateIndexes(attr_rel, tuple); /* * Because updating the pg_attribute row will trigger a relcache flush * for the target relation, we need not do anything else to notify * other backends of the change. */ heap_close(attr_rel, RowExclusiveLock); RemoveStatistics(rel, attnum); relation_close(rel, NoLock);}/* * RemoveAttrDefault * * If the specified relation/attribute has a default, remove it. * (If no default, raise error if complain is true, else return quietly.) */voidRemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain){ Relation attrdef_rel; ScanKeyData scankeys[2]; SysScanDesc scan; HeapTuple tuple; bool found = false; attrdef_rel = heap_openr(AttrDefaultRelationName, RowExclusiveLock); ScanKeyEntryInitialize(&scankeys[0], 0x0, Anum_pg_attrdef_adrelid, F_OIDEQ,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?