📄 heap.c
字号:
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_open(AttrDefaultRelationId, RowExclusiveLock); /* Find the pg_attrdef tuple */ ScanKeyInit(&scankeys[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(attrdefId)); scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndexId, 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_open(AttributeRelationId, 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 * * 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 relid){ Relation rel; /* * Open and lock the relation. */ rel = relation_open(relid, AccessExclusiveLock); /* * Schedule unlinking of the relation's physical file at commit. */ if (rel->rd_rel->relkind != RELKIND_VIEW && rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE) { RelationOpenSmgr(rel); smgrscheduleunlink(rel->rd_smgr, rel->rd_istemp); } /* * 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); /* * Forget any ON COMMIT action for the rel */ remove_on_commit_action(relid); /* * Flush the relation from the relcache. We want to do this before * starting to remove catalog entries, just to be certain that no relcache * entry rebuild will happen partway through. (That should not really * matter, since we don't do CommandCounterIncrement here, but let's be * safe.) */ RelationForgetRelation(relid); /* * remove inheritance information */ RelationRemoveInheritance(relid); /* * delete statistics */ RemoveStatistics(relid, 0); /* * delete attribute tuples */ DeleteAttributeTuples(relid); /* * delete relation tuple */ DeleteRelationTuple(relid);}/* * Store a default expression for column attnum of relation rel. * The expression must be presented as a nodeToString() string. */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_open(AttrDefaultRelationId, RowExclusiveLock); tuple = heap_formtuple(adrel->rd_att, values, nulls); attrdefOid = simple_heap_insert(adrel, tuple); CatalogUpdateIndexes(adrel, tuple); defobject.classId = AttrDefaultRelationId; 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_open(AttributeRelationId, 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 = RelationRelationId; 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 an expression tree. */ expr = stringToNode(ccbin); /* * 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 = list_length(varList); if (keycount > 0) { ListCell *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. * * Returns a list of CookedConstraint nodes that shows the cooked form of * the default and constraint expressions added to the relation. * * 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. */List *AddRelationRawConstraints(Relation rel, List *rawColDefaults, List *rawConstraints){ List *cookedConstraints = NIL; TupleDesc tupleDesc; TupleConstr *oldconstr; int numoldchecks; ParseState *pstate; RangeTblEntry *rte; int numchecks; List *checknames; ListCell *cell; Node *expr; CookedConstraint *cooked; /* * Get info about existing constraints. */ tupleDesc = RelationGetDescr(rel); oldconstr = tupleDesc->constr; if (oldconstr) numoldchecks = oldconstr->num_check; else numoldchecks = 0; /* * 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, rel, NULL, false, true); addRTEtoQuery(pstate, rte, true, true, true); /* * Process column default expressions. */ foreach(cell, rawColDefaults) { RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); 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)); cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); cooked->contype = CONSTR_DEFAULT; cooked->name = NULL; cooked->attnum = colDef->attnum; cooked->expr = expr; cookedConstraints = lappend(cookedConstraints, cooked); } /* * Process constraint expressions. */ numchecks = numoldchecks; checknames = NIL; foreach(cell, rawConstraints) { Constraint *cdef = (Constraint *) lfirst(cell); char *ccname; if (cdef->contype != CONSTR_CHECK || cdef->raw_expr == NULL) continue; Assert(cdef->cooked_expr == NULL); /* * Transform raw parsetree to executable expression. */ expr = transformExpr(pstate, cdef->raw_expr); /* * Make sure it yields a boolean result. */ expr = coerce_to_boolean(pstate, expr, "CHECK"); /* * Make sure no outside relations are referred to. */ if (list_length(pstate->p_rtable) != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("only table \"%s\" can be referenced in check constraint", RelationGetRelationName(rel)))); /* * No subplans or aggregates, either... */ if (pstate->p_hasSubLinks) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot use subquery in check constraint"))); if (pstate->p_hasAggs) ereport(ERROR, (errcode(ERRCODE_GROUPING_ERROR), errmsg("cannot use aggregate function in check constraint"))); /* * Check name uniqueness, or generate a name if none was given. */ if (cdef->name != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -