📄 heap.c
字号:
/* * 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, Oid relowner, 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; switch (relkind) { case RELKIND_RELATION: case RELKIND_INDEX: case RELKIND_TOASTVALUE: /* The relation is real, but as yet empty */ new_rel_reltup->relpages = 0; new_rel_reltup->reltuples = 0; break; case RELKIND_SEQUENCE: /* Sequences always have a known size */ new_rel_reltup->relpages = 1; new_rel_reltup->reltuples = 1; break; default: /* Views, etc, have no disk storage */ new_rel_reltup->relpages = 0; new_rel_reltup->reltuples = 0; break; } new_rel_reltup->relowner = relowner; new_rel_reltup->reltype = new_type_oid; new_rel_reltup->relkind = relkind; new_rel_desc->rd_att->tdtypeid = new_type_oid; /* ---------------- * 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 composite type corresponding to the new relation * -------------------------------- */static OidAddNewRelationType(const char *typeName, Oid typeNamespace, Oid new_rel_oid, char new_rel_kind){ return TypeCreate(typeName, /* type name */ typeNamespace, /* type namespace */ new_rel_oid, /* relation oid */ new_rel_kind, /* relation kind */ -1, /* internal size (varlena) */ '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, /* analyze procedure - default */ InvalidOid, /* array element type - irrelevant */ InvalidOid, /* domain base type - irrelevant */ NULL, /* default value - none */ NULL, /* default binary representation */ false, /* passed by reference */ 'd', /* alignment - must be the largest! */ 'x', /* fully 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, Oid reltablespace, Oid relid, Oid ownerid, TupleDesc tupdesc, char relkind, bool shared_relation, bool oidislocal, int oidinhcount, OnCommitAction oncommit, bool allow_system_table_mods){ Relation pg_class_desc; Relation new_rel_desc; Oid new_type_oid; pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock); /* * 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))); /* * Allocate an OID for the relation, unless we were told what to use. * * The OID will be the relfilenode as well, so make sure it doesn't * collide with either pg_class OIDs or existing physical files. */ if (!OidIsValid(relid)) relid = GetNewRelFileNode(reltablespace, shared_relation, pg_class_desc); /* * 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.) */ new_rel_desc = heap_create(relname, relnamespace, reltablespace, relid, tupdesc, relkind, shared_relation, allow_system_table_mods); Assert(relid == RelationGetRelid(new_rel_desc)); /* * 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. */ new_type_oid = AddNewRelationType(relname, relnamespace, relid, relkind); /* * 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. */ AddNewRelationTuple(pg_class_desc, new_rel_desc, relid, new_type_oid, ownerid, relkind); /* * now add tuples to pg_attribute for the attributes in our new relation. */ AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind, oidislocal, oidinhcount); /* * 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. * * Also make a dependency link to its owner. */ if (!IsBootstrapProcessingMode()) { ObjectAddress myself, referenced; myself.classId = RelationRelationId; myself.objectId = relid; myself.objectSubId = 0; referenced.classId = NamespaceRelationId; referenced.objectId = relnamespace; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); /* * For composite types, the dependency on owner is tracked for the * pg_type entry, so don't record it here. All other relkinds need * their ownership tracked. */ if (relkind != RELKIND_COMPOSITE_TYPE) recordDependencyOnOwner(RelationRelationId, relid, ownerid); } /* * 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(relid, 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 relid;}/* * 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(Oid relid){ Relation catalogRelation; SysScanDesc scan; ScanKeyData key; HeapTuple tuple; catalogRelation = heap_open(InheritsRelationId, RowExclusiveLock); ScanKeyInit(&key, Anum_pg_inherits_inhrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); scan = systable_beginscan(catalogRelation, InheritsRelidSeqnoIndexId, 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_open(RelationRelationId, 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_open(AttributeRelationId, RowExclusiveLock); /* Use the index to scan only attributes of the target relation */ ScanKeyInit(&key[0], Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); scan = systable_beginscan(attrel, AttributeRelidNumIndexId, 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_open(AttributeRelationId, 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); if (attnum < 0) { /* System attribute (probably OID) ... just delete the row */ simple_heap_delete(attr_rel, &tuple->t_self); } else { /* Dropping user attributes is lots harder */ /* 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); if (attnum > 0) RemoveStatistics(relid, 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_open(AttrDefaultRelationId, RowExclusiveLock); ScanKeyInit(&scankeys[0], Anum_pg_attrdef_adrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid)); ScanKeyInit(&scankeys[1], Anum_pg_attrdef_adnum, BTEqualStrategyNumber, F_INT2EQ, Int16GetDatum(attnum)); scan = systable_beginscan(attrdef_rel, AttrDefaultIndexId, true, SnapshotNow, 2, scankeys); /* There should be at most one matching tuple, but we loop anyway */ while (HeapTupleIsValid(tuple = systable_getnext(scan))) { ObjectAddress object; object.classId = AttrDefaultRelationId; object.objectId = HeapTupleGetOid(tuple);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -