heap.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,069 行 · 第 1/4 页
C
2,069 行
ObjectIdGetDatum(relid)); ScanKeyEntryInitialize(&scankeys[1], 0x0, Anum_pg_attrdef_adnum, F_INT2EQ, Int16GetDatum(attnum)); scan = systable_beginscan(attrdef_rel, AttrDefaultIndex, 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 = RelationGetRelid(attrdef_rel); object.objectId = HeapTupleGetOid(tuple); object.objectSubId = 0; performDeletion(&object, behavior); found = true; } systable_endscan(scan); heap_close(attrdef_rel, RowExclusiveLock); if (complain && !found) elog(ERROR, "could not find attrdef tuple for relation %u attnum %d", relid, attnum);}/* * RemoveAttrDefaultById * * Remove a pg_attrdef entry specified by OID. This is the guts of * attribute-default removal. Note it should be called via performDeletion, * not directly. */voidRemoveAttrDefaultById(Oid attrdefId){ Relation attrdef_rel; Relation attr_rel; Relation myrel; ScanKeyData scankeys[1]; SysScanDesc scan; HeapTuple tuple; Oid myrelid; AttrNumber myattnum; /* Grab an appropriate lock on the pg_attrdef relation */ attrdef_rel = heap_openr(AttrDefaultRelationName, RowExclusiveLock); /* Find the pg_attrdef tuple */ ScanKeyEntryInitialize(&scankeys[0], 0x0, ObjectIdAttributeNumber, F_OIDEQ, ObjectIdGetDatum(attrdefId)); scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndex, true, SnapshotNow, 1, scankeys); tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) elog(ERROR, "could not find tuple for attrdef %u", attrdefId); myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid; myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum; /* Get an exclusive lock on the relation owning the attribute */ myrel = relation_open(myrelid, AccessExclusiveLock); /* Now we can delete the pg_attrdef row */ simple_heap_delete(attrdef_rel, &tuple->t_self); systable_endscan(scan); heap_close(attrdef_rel, RowExclusiveLock); /* Fix the pg_attribute row */ attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock); tuple = SearchSysCacheCopy(ATTNUM, ObjectIdGetDatum(myrelid), Int16GetDatum(myattnum), 0, 0); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for attribute %d of relation %u", myattnum, myrelid); ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false; simple_heap_update(attr_rel, &tuple->t_self, tuple); /* keep the system catalog indexes current */ CatalogUpdateIndexes(attr_rel, tuple); /* * Our update of the pg_attribute row will force a relcache rebuild, * so there's nothing else to do here. */ heap_close(attr_rel, RowExclusiveLock); /* Keep lock on attribute's rel until end of xact */ relation_close(myrel, NoLock);}/* ---------------------------------------------------------------- * heap_drop_with_catalog - removes specified relation from catalogs * * 1) open relation, acquire exclusive lock. * 2) flush relation buffers from bufmgr * 3) remove inheritance information * 4) remove pg_statistic tuples * 5) remove pg_attribute tuples * 6) remove pg_class tuple * 7) unlink relation file * * Note that this routine is not responsible for dropping objects that are * linked to the pg_class entry via dependencies (for example, indexes and * constraints). Those are deleted by the dependency-tracing logic in * dependency.c before control gets here. In general, therefore, this routine * should never be called directly; go through performDeletion() instead. * ---------------------------------------------------------------- */voidheap_drop_with_catalog(Oid rid){ Relation rel; int i; /* * Open and lock the relation. */ rel = relation_open(rid, AccessExclusiveLock); /* * Release all buffers that belong to this relation, after writing any * that are dirty */ i = FlushRelationBuffers(rel, (BlockNumber) 0); if (i < 0) elog(ERROR, "FlushRelationBuffers returned %d", i); /* * remove inheritance information */ RelationRemoveInheritance(rel); /* * delete statistics */ RemoveStatistics(rel, 0); /* * delete attribute tuples */ DeleteAttributeTuples(RelationGetRelid(rel)); /* * delete relation tuple */ DeleteRelationTuple(RelationGetRelid(rel)); /* * forget any ON COMMIT action for the rel */ remove_on_commit_action(rid); /* * unlink the relation's physical file and finish up. */ if (rel->rd_rel->relkind != RELKIND_VIEW && rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) smgrunlink(DEFAULT_SMGR, rel); /* * Close relcache entry, but *keep* AccessExclusiveLock on the * relation until transaction commit. This ensures no one else will * try to do something with the doomed relation. */ relation_close(rel, NoLock); /* * flush the relation from the relcache */ RelationForgetRelation(rid);}/* * Store a default expression for column attnum of relation rel. * The expression must be presented as a nodeToString() string. */static voidStoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin){ Node *expr; char *adsrc; Relation adrel; HeapTuple tuple; Datum values[4]; static char nulls[4] = {' ', ' ', ' ', ' '}; Relation attrrel; HeapTuple atttup; Form_pg_attribute attStruct; Oid attrdefOid; ObjectAddress colobject, defobject; /* * Need to construct source equivalent of given node-string. */ expr = stringToNode(adbin); /* * deparse it */ adsrc = deparse_expression(expr, deparse_context_for(RelationGetRelationName(rel), RelationGetRelid(rel)), false, false); /* * Make the pg_attrdef entry. */ values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel); values[Anum_pg_attrdef_adnum - 1] = attnum; values[Anum_pg_attrdef_adbin - 1] = DirectFunctionCall1(textin, CStringGetDatum(adbin)); values[Anum_pg_attrdef_adsrc - 1] = DirectFunctionCall1(textin, CStringGetDatum(adsrc)); adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock); tuple = heap_formtuple(adrel->rd_att, values, nulls); attrdefOid = simple_heap_insert(adrel, tuple); CatalogUpdateIndexes(adrel, tuple); defobject.classId = RelationGetRelid(adrel); defobject.objectId = attrdefOid; defobject.objectSubId = 0; heap_close(adrel, RowExclusiveLock); /* now can free some of the stuff allocated above */ pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1])); pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1])); heap_freetuple(tuple); pfree(adsrc); /* * Update the pg_attribute entry for the column to show that a default * exists. */ attrrel = heap_openr(AttributeRelationName, RowExclusiveLock); atttup = SearchSysCacheCopy(ATTNUM, ObjectIdGetDatum(RelationGetRelid(rel)), Int16GetDatum(attnum), 0, 0); if (!HeapTupleIsValid(atttup)) elog(ERROR, "cache lookup failed for attribute %d of relation %u", attnum, RelationGetRelid(rel)); attStruct = (Form_pg_attribute) GETSTRUCT(atttup); if (!attStruct->atthasdef) { attStruct->atthasdef = true; simple_heap_update(attrrel, &atttup->t_self, atttup); /* keep catalog indexes current */ CatalogUpdateIndexes(attrrel, atttup); } heap_close(attrrel, RowExclusiveLock); heap_freetuple(atttup); /* * Make a dependency so that the pg_attrdef entry goes away if the * column (or whole table) is deleted. */ colobject.classId = RelOid_pg_class; colobject.objectId = RelationGetRelid(rel); colobject.objectSubId = attnum; recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO); /* * Record dependencies on objects used in the expression, too. */ recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL);}/* * Store a check-constraint expression for the given relation. * The expression must be presented as a nodeToString() string. * * Caller is responsible for updating the count of constraints * in the pg_class entry for the relation. */static voidStoreRelCheck(Relation rel, char *ccname, char *ccbin){ Node *expr; char *ccsrc; List *varList; int keycount; int16 *attNos; /* * Convert condition to a normal boolean expression tree. */ expr = stringToNode(ccbin); expr = (Node *) make_ands_explicit((List *) expr); /* * deparse it */ ccsrc = deparse_expression(expr, deparse_context_for(RelationGetRelationName(rel), RelationGetRelid(rel)), false, false); /* * Find columns of rel that are used in ccbin * * NB: pull_var_clause is okay here only because we don't allow * subselects in check constraints; it would fail to examine the * contents of subselects. */ varList = pull_var_clause(expr, false); keycount = length(varList); if (keycount > 0) { List *vl; int i = 0; attNos = (int16 *) palloc(keycount * sizeof(int16)); foreach(vl, varList) { Var *var = (Var *) lfirst(vl); int j; for (j = 0; j < i; j++) if (attNos[j] == var->varattno) break; if (j == i) attNos[i++] = var->varattno; } keycount = i; } else attNos = NULL; /* * Create the Check Constraint */ CreateConstraintEntry(ccname, /* Constraint Name */ RelationGetNamespace(rel), /* namespace */ CONSTRAINT_CHECK, /* Constraint Type */ false, /* Is Deferrable */ false, /* Is Deferred */ RelationGetRelid(rel), /* relation */ attNos, /* attrs in the constraint */ keycount, /* # attrs in the constraint */ InvalidOid, /* not a domain constraint */ InvalidOid, /* Foreign key fields */ NULL, 0, ' ', ' ', ' ', InvalidOid, /* no associated index */ expr, /* Tree form check constraint */ ccbin, /* Binary form check constraint */ ccsrc); /* Source form check constraint */ pfree(ccsrc);}/* * Store defaults and constraints passed in via the tuple constraint struct. * * NOTE: only pre-cooked expressions will be passed this way, which is to * say expressions inherited from an existing relation. Newly parsed * expressions can be added later, by direct calls to StoreAttrDefault * and StoreRelCheck (see AddRelationRawConstraints()). */static voidStoreConstraints(Relation rel, TupleDesc tupdesc){ TupleConstr *constr = tupdesc->constr; int i; if (!constr) return; /* nothing to do */ /* * Deparsing of constraint expressions will fail unless the * just-created pg_attribute tuples for this relation are made * visible. So, bump the command counter. CAUTION: this will cause a * relcache entry rebuild. */ CommandCounterIncrement(); for (i = 0; i < constr->num_defval; i++) StoreAttrDefault(rel, constr->defval[i].adnum, constr->defval[i].adbin); for (i = 0; i < constr->num_check; i++) StoreRelCheck(rel, constr->check[i].ccname, constr->check[i].ccbin); if (constr->num_check > 0) SetRelationNumChecks(rel, constr->num_check);}/* * AddRelationRawConstraints * * Add raw (not-yet-transformed) column default expressions and/or constraint * check expressions to an existing relation. This is defined to do both * for efficiency in DefineRelation, but of course you can do just one or * the other by passing empty lists. * * rel: relation to be modified * rawColDefaults: list of RawColumnDefault structures * rawConstraints: list of Constraint nodes * * All entries in rawColDefaults will be processed. Entries in rawConstraints * will be processed only if they are CONSTR_CHECK type and contain a "raw" * expression. * * NB: caller should have opened rel with AccessExclusiveLock, and should * hold that lock till end of transaction. Also, we assume the caller has * done a CommandCounterIncrement if necessary to make the relation's catalog * tuples visible. */voidAddRelationRawConstraints(Relation rel, List *rawColDefaults, List *rawConstraints){ char *relname = RelationGetRelationName(rel); TupleDesc tupleDesc; TupleConstr *oldconstr; int numoldchecks; ConstrCheck *oldchecks; ParseState *pstate; RangeTblEntry *rte; int numchecks; int constr_name_ctr = 0; List *listptr; Node *expr; /* * Get info about existing constraints. */ tupleDesc = RelationGetDescr(rel); oldconstr = tupleDesc->constr; if (oldconstr) { numoldchecks = oldconstr->num_check; oldchecks = oldconstr->check; } else { numoldchecks = 0; oldchecks = NULL; } /* * Create a dummy ParseState and insert the target relation as its * sole rangetable entry. We need a ParseState for transformExpr. */ pstate = make_parsestate(NULL); rte = addRangeTableEntryForRelation(pstate, RelationGetRelid(rel), makeAlias(relname, NIL), false, true); addRTEtoQuery(pstate, rte, true, true); /* * Process column default expressions. */ foreach(listptr, rawColDefaults) { RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr); Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1]; expr = cookDefault(pstate, colDef->raw_default, atp->atttypid, atp->atttypmod, NameStr(atp->attname)); StoreAttrDefault(rel, colDef->attnum, nodeToString(expr)); } /* * Process constraint expressions. */ numchecks = numoldchecks; foreach(listptr, rawConstraints) { Constraint *cdef = (Constraint *) lfirst(listptr); char *ccname; if (cdef->contype != CONSTR_CHECK || cdef->raw_expr == NULL) continue; Assert(cdef->cooked_expr == NULL); /* Check name uniqueness, or generate a new name */ if (cdef->name != NULL) { List *listptr2; ccname = cdef->name; /* Check against pre-existing constraints */ if (ConstraintNameIsUsed(CONSTRAINT_RELATION, RelationGetRelid(rel), RelationGetNamespace(rel), ccname)) ereport(ERROR,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?