/* *DeletionprocessingrequiresadditionalstateforeachObjectAddressthat *it'splanningtodelete.Forsimplicityandcode-sharingwemakethe *ObjectAddressescodesupportarrayswithorwithoutthisextrastate.
*/ typedefstruct
{ int flags; /* bitmask, see bit definitions below */
ObjectAddress dependee; /* object whose deletion forced this one */
} ObjectAddressExtra;
/* ObjectAddressExtra flag bits */ #define DEPFLAG_ORIGINAL 0x0001 /* an original deletion target */ #define DEPFLAG_NORMAL 0x0002 /* reached via normal dependency */ #define DEPFLAG_AUTO 0x0004 /* reached via auto dependency */ #define DEPFLAG_INTERNAL 0x0008 /* reached via internal dependency */ #define DEPFLAG_PARTITION 0x0010 /* reached via partition dependency */ #define DEPFLAG_EXTENSION 0x0020 /* reached via extension dependency */ #define DEPFLAG_REVERSE 0x0040 /* reverse internal/extension link */ #define DEPFLAG_IS_PART 0x0080 /* has a partition dependency */ #define DEPFLAG_SUBOBJECT 0x0100 /* subobject of another deletable object */
/* expansible list of ObjectAddresses */ struct ObjectAddresses
{
ObjectAddress *refs; /* => palloc'd array */
ObjectAddressExtra *extras; /* => palloc'd array, or NULL if not used */ int numrefs; /* current number of references */ int maxrefs; /* current size of palloc'd array(s) */
};
/* typedef ObjectAddresses appears in dependency.h */
/* threaded list of ObjectAddresses, for recursion detection */ typedefstruct ObjectAddressStack
{ const ObjectAddress *object; /* object being visited */ int flags; /* its current flag bits */ struct ObjectAddressStack *next; /* next outer stack level */
} ObjectAddressStack;
/* temporary storage in findDependentObjects */ typedefstruct
{
ObjectAddress obj; /* object to be deleted --- MUST BE FIRST */ int subflags; /* flags to pass down when recursing to obj */
} ObjectAddressAndFlags;
/* for find_expr_references_walker */ typedefstruct
{
ObjectAddresses *addrs; /* addresses being accumulated */
List *rtables; /* list of rangetables to resolve Vars */
} find_expr_references_context;
/* *Gothroughtheobjectsgivenrunningthefinalactionsonthem,andexecute *theactualdeletion.
*/ staticvoid
deleteObjectsInList(ObjectAddresses *targetObjects, Relation *depRel, int flags)
{ int i;
/* *Keeptrackofobjectsforeventtriggers,ifnecessary.
*/ if (trackDroppedObjectsNeeded() && !(flags & PERFORM_DELETION_INTERNAL))
{ for (i = 0; i < targetObjects->numrefs; i++)
{ const ObjectAddress *thisobj = &targetObjects->refs[i]; const ObjectAddressExtra *extra = &targetObjects->extras[i]; bool original = false; bool normal = false;
if (extra->flags & DEPFLAG_ORIGINAL)
original = true; if (extra->flags & DEPFLAG_NORMAL)
normal = true; if (extra->flags & DEPFLAG_REVERSE)
normal = true;
if (EventTriggerSupportsObject(thisobj))
{
EventTriggerSQLDropAddObject(thisobj, original, normal);
}
}
}
/* *Deletealltheobjectsintheproperorder,exceptthatiftoldto,we *shouldskiptheoriginalobject(s).
*/ for (i = 0; i < targetObjects->numrefs; i++)
{
ObjectAddress *thisobj = targetObjects->refs + i;
ObjectAddressExtra *thisextra = targetObjects->extras + i;
if ((flags & PERFORM_DELETION_SKIP_ORIGINAL) &&
(thisextra->flags & DEPFLAG_ORIGINAL)) continue;
/* *Ifthetargetobjectispinned,wecanjusterroroutimmediately;it *won'thaveanyobjectsrecordedasdependingonit.
*/ if (IsPinnedObject(object->classId, object->objectId))
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because it is required by the database system",
getObjectDescription(object, false))));
/* *Thetargetobjectmightbeinternallydependentonsomeotherobject *(its"owner"),and/orbeamemberofanextension(alsoconsideredits *owner).Ifso,andifwearen'trecursingfromtheowningobject,we *havetotransformthisdeletionrequestintoadeletionrequestofthe *owningobject.(We'lleventuallyrecursebacktothisobject,butthe *owningobjecthastobevisitedfirstsoitwillbedeletedafter.)The *waytofindoutaboutthisistoscanthepg_dependentriesthatshow *whatthisobjectdependson.
*/
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(object->classId));
ScanKeyInit(&key[1],
Anum_pg_depend_objid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(object->objectId)); if (object->objectSubId != 0)
{ /* Consider only dependencies of this sub-object */
ScanKeyInit(&key[2],
Anum_pg_depend_objsubid,
BTEqualStrategyNumber, F_INT4EQ,
Int32GetDatum(object->objectSubId));
nkeys = 3;
} else
{ /* Consider dependencies of this object and any sub-objects it has */
nkeys = 2;
}
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it",
getObjectDescription(object, false), otherObjDesc),
errhint("You can drop %s instead.", otherObjDesc)));
}
/* *Thedependentobjectmighthavebeendeletedwhilewewaitedto *lockit;ifso,wedon'tneedtodoanythingmorewithit.Wecan *testthischeaplyandindependentlyoftheobject'stypebyseeing *ifthepg_dependtuplewearelookingatisstilllive.(Ifthe *objectgotdeleted,thetuplewouldhavebeendeletedtoo.)
*/ if (!systable_recheck_tuple(scan, tup))
{ /* release the now-useless lock */
ReleaseDeletionLock(&otherObject); /* and continue scanning for dependencies */ continue;
}
/* *Wedoneedtodeleteit,soidentifyobjflagstobepasseddown, *whichdependonthedependencytype.
*/ switch (foundDep->deptype)
{ case DEPENDENCY_NORMAL:
subflags = DEPFLAG_NORMAL; break; case DEPENDENCY_AUTO: case DEPENDENCY_AUTO_EXTENSION:
subflags = DEPFLAG_AUTO; break; case DEPENDENCY_INTERNAL:
subflags = DEPFLAG_INTERNAL; break; case DEPENDENCY_PARTITION_PRI: case DEPENDENCY_PARTITION_SEC:
subflags = DEPFLAG_PARTITION; break; case DEPENDENCY_EXTENSION:
subflags = DEPFLAG_EXTENSION; break; default:
elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object, false));
subflags = 0; /* keep compiler quiet */ break;
}
/* And add it to the pending-objects list */ if (numDependentObjects >= maxDependentObjects)
{ /* enlarge array if needed */
maxDependentObjects *= 2;
dependentObjects = (ObjectAddressAndFlags *)
repalloc(dependentObjects,
maxDependentObjects * sizeof(ObjectAddressAndFlags));
}
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it",
getObjectDescription(object, false), otherObjDesc),
errhint("You can drop %s instead.", otherObjDesc)));
}
}
if (otherDesc)
{ if (numReportedClient < MAX_REPORTED_DEPS)
{ /* separate entries with a newline */ if (clientdetail.len != 0)
appendStringInfoChar(&clientdetail, '\n');
appendStringInfo(&clientdetail, _("%s depends on %s"),
objDesc, otherDesc);
numReportedClient++;
} else
numNotReportedClient++; /* separate entries with a newline */ if (logdetail.len != 0)
appendStringInfoChar(&logdetail, '\n');
appendStringInfo(&logdetail, _("%s depends on %s"),
objDesc, otherDesc);
pfree(otherDesc);
} else
numNotReportedClient++;
ok = false;
} else
{ if (numReportedClient < MAX_REPORTED_DEPS)
{ /* separate entries with a newline */ if (clientdetail.len != 0)
appendStringInfoChar(&clientdetail, '\n');
appendStringInfo(&clientdetail, _("drop cascades to %s"),
objDesc);
numReportedClient++;
} else
numNotReportedClient++; /* separate entries with a newline */ if (logdetail.len != 0)
appendStringInfoChar(&logdetail, '\n');
appendStringInfo(&logdetail, _("drop cascades to %s"),
objDesc);
}
pfree(objDesc);
}
if (numNotReportedClient > 0)
appendStringInfo(&clientdetail, ngettext("\nand %d other object " "(see server log for list)", "\nand %d other objects " "(see server log for list)",
numNotReportedClient),
numNotReportedClient);
if (!ok)
{ if (origObject)
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because other objects depend on it",
getObjectDescription(origObject, false)),
errdetail_internal("%s", clientdetail.data),
errdetail_log("%s", logdetail.data),
errhint("Use DROP ... CASCADE to drop the dependent objects too."))); else
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop desired object(s) because other objects depend on them"),
errdetail_internal("%s", clientdetail.data),
errdetail_log("%s", logdetail.data),
errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
} elseif (numReportedClient > 1)
{
ereport(msglevel,
(errmsg_plural("drop cascades to %d other object", "drop cascades to %d other objects",
numReportedClient + numNotReportedClient,
numReportedClient + numNotReportedClient),
errdetail_internal("%s", clientdetail.data),
errdetail_log("%s", logdetail.data)));
} elseif (numReportedClient == 1)
{ /* we just use the single item as-is */
ereport(msglevel,
(errmsg_internal("%s", clientdetail.data)));
}
/* we expect exactly one match */
tup = systable_getnext(scan); if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for %s %u",
get_object_class_descr(object->classId), object->objectId);
case ProcedureRelationId:
RemoveFunctionById(object->objectId); break;
case TypeRelationId:
RemoveTypeById(object->objectId); break;
case ConstraintRelationId:
RemoveConstraintById(object->objectId); break;
case AttrDefaultRelationId:
RemoveAttrDefaultById(object->objectId); break;
case LargeObjectRelationId:
LargeObjectDrop(object->objectId); break;
case OperatorRelationId:
RemoveOperatorById(object->objectId); break;
case RewriteRelationId:
RemoveRewriteRuleById(object->objectId); break;
case TriggerRelationId:
RemoveTriggerById(object->objectId); break;
case StatisticExtRelationId:
RemoveStatisticsById(object->objectId); break;
case TSConfigRelationId:
RemoveTSConfigurationById(object->objectId); break;
case ExtensionRelationId:
RemoveExtensionById(object->objectId); break;
case PolicyRelationId:
RemovePolicyById(object->objectId); break;
case PublicationNamespaceRelationId:
RemovePublicationSchemaById(object->objectId); break;
case PublicationRelRelationId:
RemovePublicationRelById(object->objectId); break;
case PublicationRelationId:
RemovePublicationById(object->objectId); break;
case CastRelationId: case CollationRelationId: case ConversionRelationId: case LanguageRelationId: case OperatorClassRelationId: case OperatorFamilyRelationId: case AccessMethodRelationId: case AccessMethodOperatorRelationId: case AccessMethodProcedureRelationId: case NamespaceRelationId: case TSParserRelationId: case TSDictionaryRelationId: case TSTemplateRelationId: case ForeignDataWrapperRelationId: case ForeignServerRelationId: case UserMappingRelationId: case DefaultAclRelationId: case EventTriggerRelationId: case TransformRelationId: case AuthMemRelationId:
DropObjectById(object); break;
/* *Theseglobalobjecttypesarenotsupportedhere.
*/ case AuthIdRelationId: case DatabaseRelationId: case TableSpaceRelationId: case SubscriptionRelationId: case ParameterAclRelationId:
elog(ERROR, "global objects cannot be deleted by doDeletion"); break;
/* We gin up a rather bogus rangetable list to handle Vars */
rte.type = T_RangeTblEntry;
rte.rtekind = RTE_RELATION;
rte.relid = relId;
rte.relkind = RELKIND_RELATION; /* no need for exactness here */
rte.rellockmode = AccessShareLock;
context.rtables = list_make1(list_make1(&rte));
/* Scan the expression tree for referenceable objects */
find_expr_references_walker(expr, &context);
/* Remove any duplicates */
eliminate_duplicate_dependencies(context.addrs);
/* Separate self-dependencies if necessary */ if ((behavior != self_behavior || reverse_self) &&
context.addrs->numrefs > 0)
{
ObjectAddresses *self_addrs;
ObjectAddress *outobj; int oldref,
outrefs;
if (thisobj->classId == RelationRelationId &&
thisobj->objectId == relId)
{ /* Move this ref into self_addrs */
add_exact_object_address(thisobj, self_addrs);
} else
{ /* Keep it in context.addrs */
*outobj = *thisobj;
outobj++;
outrefs++;
}
}
context.addrs->numrefs = outrefs;
/* Record the self-dependencies with the appropriate direction */ if (!reverse_self)
recordMultipleDependencies(depender,
self_addrs->refs, self_addrs->numrefs,
self_behavior); else
{ /* Can't use recordMultipleDependencies, so do it the hard way */ int selfref;
/* Record the external dependencies */
recordMultipleDependencies(depender,
context.addrs->refs, context.addrs->numrefs,
behavior);
free_object_addresses(context.addrs);
}
/* *Recursivelysearchanexpressiontreeforobjectreferences. * *Note:inmanycaseswedonotneedtocreatedependenciesonthedatatypes *involvedinanexpression,becausewe'llhaveanindirectdependencyvia *someotherobject.ForinstanceVarnodesdependonacolumnwhichdepends *onthedatatype,andOpExprnodesdependontheoperatorwhichdependson *thedatatype.Howeverwedoneedatypedependencyifthereisnosuch *indirectdependency,asforexampleinConstandCoerceToDomainnodes. * *Similarly,wedon'tneedtocreatedependenciesoncollationsexceptwhere *thecollationisbeingfreshlyintroducedtotheexpression.
*/ staticbool
find_expr_references_walker(Node *node,
find_expr_references_context *context)
{ if (node == NULL) returnfalse; if (IsA(node, Var))
{
Var *var = (Var *) node;
List *rtable;
RangeTblEntry *rte;
/* Find matching rtable entry, or complain if not found */ if (var->varlevelsup >= list_length(context->rtables))
elog(ERROR, "invalid varlevelsup %d", var->varlevelsup);
rtable = (List *) list_nth(context->rtables, var->varlevelsup); if (var->varno <= 0 || var->varno > list_length(rtable))
elog(ERROR, "invalid varno %d", var->varno);
rte = rt_fetch(var->varno, rtable);
/* *Awhole-rowVarreferencesnospecificcolumns,soaddsnonew *dependency.(Weassumethatthereisawhole-tabledependency *arisingfromeachunderlyingrangetableentry.Whilewecould *recordsuchadependencywhenfindingawhole-rowVarthat *referencesarelationdirectly,it'squiteunclearhowtoextend *thattowhole-rowVarsforJOINs,soitseemsbettertoleavethe *responsibilitywiththerangetable.Notethatthisposessome *risksforidentifyingdependenciesofstand-aloneexpressions: *whole-tablereferencesmayneedtobecreatedseparately.)
*/ if (var->varattno == InvalidAttrNumber) returnfalse; if (rte->rtekind == RTE_RELATION)
{ /* If it's a plain relation, reference this column */
add_object_address(RelationRelationId, rte->relid, var->varattno,
context->addrs);
} elseif (rte->rtekind == RTE_FUNCTION)
{ /* Might need to add a dependency on a composite type's column */ /* (done out of line, because it's a bit bulky) */
process_function_rte_ref(rte, var->varattno, context);
}
/* *Ifit'saregclassorsimilarliteralreferringtoanexisting *object,addareferencetothatobject.(Currently,onlythe *regclassandregconfigcaseshaveanylikelyuse,butwemayas *wellhandlealltheOID-aliasdatatypesconsistently.)
*/ if (!con->constisnull)
{ switch (con->consttype)
{ case REGPROCOID: case REGPROCEDUREOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(PROCOID,
ObjectIdGetDatum(objoid)))
add_object_address(ProcedureRelationId, objoid, 0,
context->addrs); break; case REGOPEROID: case REGOPERATOROID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(OPEROID,
ObjectIdGetDatum(objoid)))
add_object_address(OperatorRelationId, objoid, 0,
context->addrs); break; case REGCLASSOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(RELOID,
ObjectIdGetDatum(objoid)))
add_object_address(RelationRelationId, objoid, 0,
context->addrs); break; case REGTYPEOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(TYPEOID,
ObjectIdGetDatum(objoid)))
add_object_address(TypeRelationId, objoid, 0,
context->addrs); break; case REGCOLLATIONOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(COLLOID,
ObjectIdGetDatum(objoid)))
add_object_address(CollationRelationId, objoid, 0,
context->addrs); break; case REGCONFIGOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(TSCONFIGOID,
ObjectIdGetDatum(objoid)))
add_object_address(TSConfigRelationId, objoid, 0,
context->addrs); break; case REGDICTIONARYOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(TSDICTOID,
ObjectIdGetDatum(objoid)))
add_object_address(TSDictionaryRelationId, objoid, 0,
context->addrs); break;
case REGNAMESPACEOID:
objoid = DatumGetObjectId(con->constvalue); if (SearchSysCacheExists1(NAMESPACEOID,
ObjectIdGetDatum(objoid)))
add_object_address(NamespaceRelationId, objoid, 0,
context->addrs); break;
/* *Dependenciesforregroleshouldbesharedamongall *databases,soexplicitlyinhibittohavedependencies.
*/ case REGROLEOID:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("constant of the type %s cannot be used here", "regrole"))); break;
}
} returnfalse;
} elseif (IsA(node, Param))
{
Param *param = (Param *) node;
/* A parameter must depend on the parameter's datatype */
add_object_address(TypeRelationId, param->paramtype, 0,
context->addrs); /* and its collation, just as for Consts */ if (OidIsValid(param->paramcollid) &&
param->paramcollid != DEFAULT_COLLATION_OID)
add_object_address(CollationRelationId, param->paramcollid, 0,
context->addrs);
} elseif (IsA(node, FuncExpr))
{
FuncExpr *funcexpr = (FuncExpr *) node;
add_object_address(ProcedureRelationId, funcexpr->funcid, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, OpExpr))
{
OpExpr *opexpr = (OpExpr *) node;
add_object_address(OperatorRelationId, opexpr->opno, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, DistinctExpr))
{
DistinctExpr *distinctexpr = (DistinctExpr *) node;
add_object_address(OperatorRelationId, distinctexpr->opno, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, NullIfExpr))
{
NullIfExpr *nullifexpr = (NullIfExpr *) node;
add_object_address(OperatorRelationId, nullifexpr->opno, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
add_object_address(OperatorRelationId, opexpr->opno, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, Aggref))
{
Aggref *aggref = (Aggref *) node;
add_object_address(ProcedureRelationId, aggref->aggfnoid, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, WindowFunc))
{
WindowFunc *wfunc = (WindowFunc *) node;
add_object_address(ProcedureRelationId, wfunc->winfnoid, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, SubscriptingRef))
{
SubscriptingRef *sbsref = (SubscriptingRef *) node;
/* *Therefexprshouldprovideadequatedependencyonrefcontainertype, *andthattypeinturndependsonrefelemtype.However,acustom *subscriptinghandlermightsetrefrestypetosomethingdifferent *fromeitherofthose,inwhichcasewe'dbetterrecordit.
*/ if (sbsref->refrestype != sbsref->refcontainertype &&
sbsref->refrestype != sbsref->refelemtype)
add_object_address(TypeRelationId, sbsref->refrestype, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, SubPlan))
{ /* Extra work needed here if we ever need this case */
elog(ERROR, "already-planned subqueries not supported");
} elseif (IsA(node, FieldSelect))
{
FieldSelect *fselect = (FieldSelect *) node;
Oid argtype = getBaseType(exprType((Node *) fselect->arg));
Oid reltype = get_typ_typrelid(argtype);
/* *WeneedadependencyonthespecificcolumnnamedinFieldSelect, *assumingwecanidentifythepg_classOIDforit.(Probablywe *alwayscanatthemoment,butinfutureitmightbepossiblefor *argtypetobeRECORDOID.)Ifwecanmakeacolumndependencythen *weshouldn'tneedadependencyonthecolumn'stype;butifwe *can't,makeadependencyonthetype,asitmightnotappear *anywhereelseintheexpression.
*/ if (OidIsValid(reltype))
add_object_address(RelationRelationId, reltype, fselect->fieldnum,
context->addrs); else
add_object_address(TypeRelationId, fselect->resulttype, 0,
context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(fselect->resultcollid) &&
fselect->resultcollid != DEFAULT_COLLATION_OID)
add_object_address(CollationRelationId, fselect->resultcollid, 0,
context->addrs);
} elseif (IsA(node, FieldStore))
{
FieldStore *fstore = (FieldStore *) node;
Oid reltype = get_typ_typrelid(fstore->resulttype);
/* similar considerations to FieldSelect, but multiple column(s) */ if (OidIsValid(reltype))
{
ListCell *l;
/* since there is no function dependency, need to depend on type */
add_object_address(TypeRelationId, relab->resulttype, 0,
context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(relab->resultcollid) &&
relab->resultcollid != DEFAULT_COLLATION_OID)
add_object_address(CollationRelationId, relab->resultcollid, 0,
context->addrs);
} elseif (IsA(node, CoerceViaIO))
{
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
/* since there is no exposed function, need to depend on type */
add_object_address(TypeRelationId, iocoerce->resulttype, 0,
context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(iocoerce->resultcollid) &&
iocoerce->resultcollid != DEFAULT_COLLATION_OID)
add_object_address(CollationRelationId, iocoerce->resultcollid, 0,
context->addrs);
} elseif (IsA(node, ArrayCoerceExpr))
{
ArrayCoerceExpr *acoerce = (ArrayCoerceExpr *) node;
/* as above, depend on type */
add_object_address(TypeRelationId, acoerce->resulttype, 0,
context->addrs); /* the collation might not be referenced anywhere else, either */ if (OidIsValid(acoerce->resultcollid) &&
acoerce->resultcollid != DEFAULT_COLLATION_OID)
add_object_address(CollationRelationId, acoerce->resultcollid, 0,
context->addrs); /* fall through to examine arguments */
} elseif (IsA(node, ConvertRowtypeExpr))
{
ConvertRowtypeExpr *cvt = (ConvertRowtypeExpr *) node;
/* since there is no function dependency, need to depend on type */
add_object_address(TypeRelationId, cvt->resulttype, 0,
context->addrs);
} elseif (IsA(node, CollateExpr))
{
CollateExpr *coll = (CollateExpr *) node;
if (!IsA(aliasvar, Var))
find_expr_references_walker(aliasvar, context);
}
context->rtables = list_delete_first(context->rtables); break; case RTE_NAMEDTUPLESTORE:
/* *Catalogedobjectscannotdependontuplestores,because *thosehavenocatalogedrepresentation.Fornowwecan *callthetuplestorea"transitiontable"becausethat's *theonlykindexposedtoSQL,butsomedaywemighthave *toworkharder.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("transition table \"%s\" cannot be referenced in a persistent object",
rte->eref->aliasname))); break; default: /* Other RTE types can be ignored here */ break;
}
}
/* we need to look at the groupClauses for operator references */
find_expr_references_walker((Node *) setop->groupClauses, context); /* fall through to examine child nodes */
} elseif (IsA(node, RangeTblFunction))
{
RangeTblFunction *rtfunc = (RangeTblFunction *) node;
ListCell *ct;
/* If it has a coldeflist, it certainly returns RECORD */ if (rtfunc->funccolnames != NIL)
tupdesc = NULL; /* no need to work hard */ else
tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true); if (tupdesc && tupdesc->tdtypeid != RECORDOID)
{ /* *Namedcompositetype,soindividualcolumnscouldget *dropped.Makeadependencyonthisspecificcolumn.
*/
Oid reltype = get_typ_typrelid(tupdesc->tdtypeid);
Assert(attnum - atts_done <= tupdesc->natts); if (OidIsValid(reltype)) /* can this fail? */
add_object_address(RelationRelationId, reltype,
attnum - atts_done,
context->addrs); return;
} /* Nothing to do; function's result type is handled elsewhere */ return;
}
atts_done += rtfunc->funccolcount;
}
/* If we get here, must be looking for the ordinality column */ if (rte->funcordinality && attnum == atts_done + 1) return;
/* this probably can't happen ... */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column %d of relation \"%s\" does not exist",
attnum, rte->eref->aliasname)));
}
if (priorobj->classId == thisobj->classId &&
priorobj->objectId == thisobj->objectId)
{ if (priorobj->objectSubId == thisobj->objectSubId) continue; /* identical, so drop thisobj */
/* *Ifwehaveawhole-objectreferenceandareferencetoapart *ofthesameobject,wedon'tneedthewhole-objectreference *(forexample,wedon'tneedtoreferencebothtablefooand *columnfoo.bar).Thewhole-objectreferencewillalwaysappear *firstinthesortedlist.
*/ if (priorobj->objectSubId == 0)
{ /* replace whole ref with partial */
priorobj->objectSubId = thisobj->objectSubId; continue;
}
} /* Not identical, so add thisobj to output set */
priorobj++;
*priorobj = *thisobj;
newrefs++;
}
/* allocate extra space if first time */ if (!addrs->extras)
addrs->extras = (ObjectAddressExtra *)
palloc(addrs->maxrefs * sizeof(ObjectAddressExtra));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.