*
* pg_depend.cpp
* routines to support manipulation of the pg_depend relation
*
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
* Portions Copyright (c) 2021, openGauss Contributors
*
*
* IDENTIFICATION
* src/common/backend/catalog/pg_depend.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/transam.h"
#include "catalog/dependency.h"
#include "catalog/gs_package.h"
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_synonym.h"
#include "commands/extension.h"
#include "miscadmin.h"
#include "storage/tcap.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/rel_gs.h"
#include "utils/snapmgr.h"
#include "utils/builtins.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_proc_ext.h"
#include "catalog/pg_rewrite.h"
#include "catalog/gs_dependencies_fn.h"
#include "catalog/gs_dependencies_obj.h"
#include "catalog/pg_object.h"
static bool isObjectPinned(const ObjectAddress* object, Relation rel);
* Record a dependency between 2 objects via their respective objectAddress.
* The first argument is the dependent object, the second the one it
* references.
*
* This simply creates an entry in pg_depend, without any other processing.
*/
void recordDependencyOn(const ObjectAddress* depender, const ObjectAddress* referenced, DependencyType behavior,
GsDependParamBody* gsdependParamBody)
{
recordMultipleDependencies(depender, referenced, 1, behavior, gsdependParamBody);
}
* Record multiple dependencies (of the same kind) for a single dependent
* object. This has a little less overhead than recording each separately.
*/
void recordMultipleDependencies(
const ObjectAddress* depender, const ObjectAddress* referenced, int nreferenced, DependencyType behavior,
GsDependParamBody* gsdependParamBody)
{
Relation dependDesc;
CatalogIndexState indstate;
HeapTuple tup;
int i;
bool nulls[Natts_pg_depend];
Datum values[Natts_pg_depend];
if (nreferenced <= 0)
return;
* During bootstrap, do nothing since pg_depend may not exist yet. initdb
* will fill in appropriate pg_depend entries after bootstrap.
*/
if (IsBootstrapProcessingMode())
return;
dependDesc = heap_open(DependRelationId, RowExclusiveLock);
indstate = NULL;
errno_t rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "", "");
TrForbidAccessRbDependencies(dependDesc, depender, referenced, nreferenced);
for (i = 0; i < nreferenced; i++, referenced++) {
* If the referenced object is pinned by the system, there's no real
* need to record dependencies on it. This saves lots of space in
* pg_depend, so it's worth the time taken to check.
*/
bool isPinned = isObjectPinned(referenced, dependDesc);
if (enable_plpgsql_gsdependency() && DEPENDENCY_NORMAL == behavior &&
gsplsql_need_build_gs_dependency(gsdependParamBody, referenced, isPinned)) {
bool ret = gsplsql_build_gs_type_dependency(gsdependParamBody, referenced);
if (ret) {
gsdependParamBody->hasDependency = true;
}
}
if (isPinned) {
continue;
}
if (!enable_plpgsql_gsdependency() || NULL == gsdependParamBody ||
(GSDEPEND_REFOBJ_POS_IN_TYPE == gsdependParamBody->refPosType
&& GSDEPEND_OBJECT_TYPE_TYPE == gsdependParamBody->type)) {
* Record the Dependency. Note we don't bother to check for
* duplicate dependencies; there's no harm in them.
*/
values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(depender->classId);
values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(depender->objectId);
values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(depender->objectSubId);
values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(referenced->classId);
values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(referenced->objectId);
values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(referenced->objectSubId);
values[Anum_pg_depend_deptype - 1] = CharGetDatum((char)behavior);
if (depender->classId == RewriteRelationId && referenced->classId == ProcedureRelationId &&
referenced->depsrc != NULL) {
values[Anum_pg_depend_depsrc - 1] = CStringGetTextDatum(referenced->depsrc);
} else {
nulls[Anum_pg_depend_depsrc - 1] = true;
}
tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
(void)simple_heap_insert(dependDesc, tup);
if (indstate == NULL)
indstate = CatalogOpenIndexes(dependDesc);
CatalogIndexInsert(indstate, tup);
heap_freetuple_ext(tup);
}
}
if (indstate != NULL)
CatalogCloseIndexes(indstate);
heap_close(dependDesc, RowExclusiveLock);
}
* If we are executing a CREATE EXTENSION operation, mark the given object
* as being a member of the extension. Otherwise, do nothing.
*
* This must be called during creation of any user-definable object type
* that could be a member of an extension.
*
* If isReplace is true, the object already existed (or might have already
* existed), so we must check for a pre-existing extension membership entry.
* Passing false is a guarantee that the object is newly created, and so
* could not already be a member of any extension.
*/
void recordDependencyOnCurrentExtension(const ObjectAddress* object, bool isReplace)
{
Assert(object->objectSubId == 0);
if (creating_extension) {
ObjectAddress extension;
if (isReplace) {
Oid oldext;
oldext = getExtensionOfObject(object->classId, object->objectId);
if (OidIsValid(oldext)) {
if (oldext == u_sess->cmd_cxt.CurrentExtensionObject)
return;
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(object),
get_extension_name(oldext))));
}
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is not a member of extension \"%s\"",
getObjectDescription(object),
get_extension_name(u_sess->cmd_cxt.CurrentExtensionObject)),
errdetail("An extension is not allowed to replace an object that it does not own.")));
}
extension.classId = ExtensionRelationId;
extension.objectId = u_sess->cmd_cxt.CurrentExtensionObject;
extension.objectSubId = 0;
recordDependencyOn(object, &extension, DEPENDENCY_EXTENSION);
}
}
* If we are executing a CREATE EXTENSION operation, check that the given
* object is a member of the extension, and throw an error if it isn't.
* Otherwise, do nothing.
*
* This must be called whenever a CREATE IF NOT EXISTS operation (for an
* object type that can be an extension member) has found that an object of
* the desired name already exists. It is insecure for an extension to use
* IF NOT EXISTS except when the conflicting object is already an extension
* member; otherwise a hostile user could substitute an object with arbitrary
* properties.
*/
void checkMembershipInCurrentExtension(const ObjectAddress *object)
{
* This is actually the same condition tested in
* recordDependencyOnCurrentExtension; but we want to issue a
* differently-worded error, and anyway it would be pretty confusing to
* call recordDependencyOnCurrentExtension in these circumstances.
*/
Assert(object->objectSubId == 0);
if (creating_extension) {
Oid oldext;
oldext = getExtensionOfObject(object->classId, object->objectId);
if (oldext == u_sess->cmd_cxt.CurrentExtensionObject)
return;
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is not a member of extension \"%s\"",
getObjectDescription(object),
get_extension_name(u_sess->cmd_cxt.CurrentExtensionObject)),
errdetail("An extension may only use CREATE ... IF NOT EXISTS to skip object creation"
"if the conflicting object is one that it already owns.")));
}
}
* Record pinned dependency for fabricated system tables during in-place upgrade.
*/
void recordPinnedDependency(const ObjectAddress* object)
{
Relation dependDesc;
CatalogIndexState indstate;
HeapTuple tup;
bool nulls[Natts_pg_depend];
Datum values[Natts_pg_depend];
errno_t errorno = EOK;
* During bootstrap, do nothing since pg_depend may not exist yet. initdb
* will fill in appropriate pg_depend entries after bootstrap.
*/
if (IsBootstrapProcessingMode())
return;
dependDesc = heap_open(DependRelationId, RowExclusiveLock);
indstate = NULL;
errorno = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(errorno, "\0", "\0");
* Record the Dependency. Note we don't bother to check for
* duplicate dependencies; there's no harm in them.
*/
values[Anum_pg_depend_classid - 1] = ObjectIdGetDatum(InvalidOid);
values[Anum_pg_depend_objid - 1] = ObjectIdGetDatum(InvalidOid);
values[Anum_pg_depend_objsubid - 1] = Int32GetDatum(InvalidOid);
values[Anum_pg_depend_refclassid - 1] = ObjectIdGetDatum(object->classId);
values[Anum_pg_depend_refobjid - 1] = ObjectIdGetDatum(object->objectId);
values[Anum_pg_depend_refobjsubid - 1] = Int32GetDatum(object->objectSubId);
values[Anum_pg_depend_deptype - 1] = CharGetDatum((char)DEPENDENCY_PIN);
nulls[Anum_pg_depend_depsrc - 1] = true;
tup = heap_form_tuple(dependDesc->rd_att, values, nulls);
(void)simple_heap_insert(dependDesc, tup);
if (indstate == NULL)
indstate = CatalogOpenIndexes(dependDesc);
CatalogIndexInsert(indstate, tup);
heap_freetuple_ext(tup);
if (indstate != NULL)
CatalogCloseIndexes(indstate);
heap_close(dependDesc, RowExclusiveLock);
}
* deleteDependencyRecordsFor -- delete all records with given depender
* classId/objectId. Returns the number of records deleted.
*
* This is used when redefining an existing object. Links leading to the
* object do not change, and links leading from it will be recreated
* (possibly with some differences from before).
*
* If skipExtensionDeps is true, we do not delete any dependencies that
* show that the given object is a member of an extension. This avoids
* needing a lot of extra logic to fetch and recreate that dependency.
*/
long deleteDependencyRecordsFor(Oid classId, Oid objectId, bool skipExtensionDeps)
{
long count = 0;
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId));
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
if (skipExtensionDeps && ((Form_pg_depend)GETSTRUCT(tup))->deptype == DEPENDENCY_EXTENSION)
continue;
simple_heap_delete(depRel, &tup->t_self);
count++;
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
CommandCounterIncrement();
return count;
}
* deleteDependencyRecordsForClass -- delete all records with given depender
* classId/objectId, dependee classId, and deptype.
* Returns the number of records deleted.
*
* This is a variant of deleteDependencyRecordsFor, useful when revoking
* an object property that is expressed by a dependency record (such as
* extension membership).
*/
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
{
long count = 0;
Relation depRel = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId));
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
Form_pg_depend depform = (Form_pg_depend)GETSTRUCT(tup);
if (depform->refclassid == refclassId && depform->deptype == deptype) {
simple_heap_delete(depRel, &tup->t_self);
count++;
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
return count;
}
* Adjust dependency record(s) to point to a different object of the same type
*
* classId/objectId specify the referencing object.
* refClassId/oldRefObjectId specify the old referenced object.
* newRefObjectId is the new referenced object (must be of class refClassId).
*
* Note the lack of objsubid parameters. If there are subobject references
* they will all be readjusted.
*
* Returns the number of records updated.
*/
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
{
long count = 0;
Relation depRel = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
ObjectAddress objAddr;
bool newIsPinned = false;
depRel = heap_open(DependRelationId, RowExclusiveLock);
* If oldRefObjectId is pinned, there won't be any dependency entries on
* it --- we can't cope in that case. (This isn't really worth expending
* code to fix, in current usage; it just means you can't rename stuff out
* of pg_catalog, which would likely be a bad move anyway.)
*/
objAddr.classId = refClassId;
objAddr.objectId = oldRefObjectId;
objAddr.objectSubId = 0;
if (isObjectPinned(&objAddr, depRel))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg(
"cannot remove dependency on %s because it is a system object", getObjectDescription(&objAddr))));
* We can handle adding a dependency on something pinned, though, since
* that just means deleting the dependency entry.
*/
objAddr.objectId = newRefObjectId;
newIsPinned = isObjectPinned(&objAddr, depRel);
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId));
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan)))) {
Form_pg_depend depform = (Form_pg_depend)GETSTRUCT(tup);
if (depform->refclassid == refClassId && depform->refobjid == oldRefObjectId) {
if (newIsPinned)
simple_heap_delete(depRel, &tup->t_self);
else {
tup = heap_copytuple(tup);
depform = (Form_pg_depend)GETSTRUCT(tup);
depform->refobjid = newRefObjectId;
simple_heap_update(depRel, &tup->t_self, tup);
CatalogUpdateIndexes(depRel, tup);
heap_freetuple_ext(tup);
}
count++;
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
return count;
}
bool IsPinnedObject(Oid classOid, Oid objOid) {
ObjectAddress objAddr;
objAddr.classId = classOid;
objAddr.objectId = objOid;
objAddr.objectSubId = 0;
Relation dependDesc = heap_open(DependRelationId, AccessShareLock);
bool isPinned = isObjectPinned(&objAddr, dependDesc);
heap_close(dependDesc, AccessShareLock);
return isPinned;
}
* Adjust all dependency records to come from a different object of the same type
*
* classId/oldObjectId specify the old referencing object.
* newObjectId is the new referencing object (must be of class classId).
*/
void changeDependenciesOf(Oid classId, Oid oldObjectId, Oid newObjectId)
{
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(classId));
ScanKeyInit(&key[1],
Anum_pg_depend_objid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(oldObjectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
tup = heap_copytuple(tup);
depform = (Form_pg_depend) GETSTRUCT(tup);
depform->objid = newObjectId;
simple_heap_update(depRel, &tup->t_self, tup);
CatalogUpdateIndexes(depRel, tup);
heap_freetuple_ext(tup);
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
}
* Adjust all dependency records to point to a different object of the same type
*
* refClassId/oldRefObjectId specify the old referenced object.
* newRefObjectId is the new referenced object (must be of class refClassId).
*/
void changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
{
Relation depRel = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
ObjectAddress objAddr;
bool newIsPinned = false;
depRel = heap_open(DependRelationId, RowExclusiveLock);
* If oldRefObjectId is pinned, there won't be any dependency entries on
* it --- we can't cope in that case. (This isn't really worth expending
* code to fix, in current usage; it just means you can't rename stuff out
* of pg_catalog, which would likely be a bad move anyway.)
*/
objAddr.classId = refClassId;
objAddr.objectId = oldRefObjectId;
objAddr.objectSubId = 0;
if (isObjectPinned(&objAddr, depRel))
ereport (ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot remove dependency on %s because it is a system object",
getObjectDescription(&objAddr))));
* We can handle adding a dependency on something pinned, though, since
* that just means deleting the dependency entry.
*/
objAddr.objectId = newRefObjectId;
newIsPinned = isObjectPinned(&objAddr, depRel);
ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(refClassId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(oldRefObjectId));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
if(newIsPinned)
simple_heap_delete(depRel, &tup->t_self);
else {
tup = heap_copytuple(tup);
depform = (Form_pg_depend) GETSTRUCT(tup);
depform->refobjid = newRefObjectId;
simple_heap_update(depRel, &tup->t_self, tup);
CatalogUpdateIndexes(depRel, tup);
heap_freetuple_ext(tup);
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
}
* isObjectPinned()
*
* Test if an object is required for basic database functionality.
* Caller must already have opened pg_depend.
*
* The passed subId, if any, is ignored; we assume that only whole objects
* are pinned (and that this implies pinning their components).
*/
static bool isObjectPinned(const ObjectAddress* object, Relation rel)
{
bool ret = false;
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
ScanKeyData key[2];
* pinned in pg_proc because we delete them from pg_proc
*/
if (object->classId == ProcedureRelationId && IsSystemObjOid(object->objectId)) {
return true;
}
ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->classId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
scan = systable_beginscan(rel, DependReferenceIndexId, true, NULL, 2, key);
* Since we won't generate additional pg_depend entries for pinned
* objects, there can be at most one entry referencing a pinned object.
* Hence, it's sufficient to look at the first returned tuple; we don't
* need to loop.
*/
tup = systable_getnext(scan);
if (HeapTupleIsValid(tup)) {
Form_pg_depend foundDep = (Form_pg_depend)GETSTRUCT(tup);
if (foundDep->deptype == DEPENDENCY_PIN)
ret = true;
}
systable_endscan(scan);
return ret;
}
* Various special-purpose lookups and manipulations of pg_depend.
*/
* Find the extension containing the specified object, if any
*
* Returns the OID of the extension, or InvalidOid if the object does not
* belong to any extension.
*
* Extension membership is marked by an EXTENSION dependency from the object
* to the extension. Note that the result will be indeterminate if pg_depend
* contains links from this object to more than one extension ... but that
* should never happen.
*/
Oid getExtensionOfObject(Oid classId, Oid objectId)
{
Oid result = InvalidOid;
Relation depRel = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId));
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan)))) {
Form_pg_depend depform = (Form_pg_depend)GETSTRUCT(tup);
if (depform->refclassid == ExtensionRelationId && depform->deptype == DEPENDENCY_EXTENSION) {
result = depform->refobjid;
break;
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return result;
}
* Detect whether a sequence is marked as "owned" by a column
*
* An ownership marker is an AUTO dependency from the sequence to the
* column. If we find one, store the identity of the owning column
* into *tableId and *colId and return TRUE; else return FALSE.
*
* Note: if there's more than one such pg_depend entry then you get
* a random one of them returned into the out parameters. This should
* not happen, though.
*/
bool sequenceIsOwned(Oid seqId, Oid* tableId, int32* colId)
{
bool ret = false;
Relation depRel = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(seqId));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan)))) {
Form_pg_depend depform = (Form_pg_depend)GETSTRUCT(tup);
if (depform->refclassid == RelationRelationId && depform->deptype == DEPENDENCY_AUTO) {
*tableId = depform->refobjid;
*colId = depform->refobjsubid;
ret = true;
break;
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return ret;
}
* Remove any existing "owned" markers for the specified sequence.
*
* Note: we don't provide a special function to install an "owned"
* marker; just use recordDependencyOn().
*/
void markSequenceUnowned(Oid seqId)
{
(void)deleteDependencyRecordsForClass(RelationRelationId, seqId, RelationRelationId, DEPENDENCY_AUTO);
}
* Collect a list of OIDs of all sequences owned by the specified relation.
*/
List* getOwnedSequences(Oid relid, List* attrList)
{
List* result = NIL;
Relation depRel = NULL;
ScanKeyData key[2];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(
&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(relid));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
Form_pg_depend deprec = (Form_pg_depend)GETSTRUCT(tup);
* We assume any auto dependency of a sequence on a column must be
* what we are looking for. (We need the relkind test because indexes
* can also have auto dependencies on columns.)
*/
if (deprec->classid == RelationRelationId && deprec->objsubid == 0 && deprec->refobjsubid != 0 &&
deprec->deptype == DEPENDENCY_AUTO && RELKIND_IS_SEQUENCE(get_rel_relkind(deprec->objid))) {
if (attrList != NULL) {
if (list_member_int(attrList, deprec->refobjsubid))
result = lappend_oid(result, deprec->objid);
} else {
result = lappend_oid(result, deprec->objid);
}
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return result;
}
* get_constraint_index
* Given the OID of a unique or primary-key constraint, return the
* OID of the underlying unique index.
*
* Return InvalidOid if the index couldn't be found; this suggests the
* given OID is bogus, but we leave it to caller to decide what to do.
*/
Oid get_constraint_index(Oid constraintId)
{
Oid indexId = InvalidOid;
Relation depRel = NULL;
ScanKeyData key[3];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
char relkind;
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(
&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ConstraintRelationId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(constraintId));
ScanKeyInit(&key[2], Anum_pg_depend_refobjsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(0));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 3, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
Form_pg_depend deprec = (Form_pg_depend)GETSTRUCT(tup);
* We assume any internal dependency of an index on the constraint
* must be what we are looking for. (The relkind test is just
* paranoia; there shouldn't be any such dependencies otherwise.)
*/
if (deprec->classid == RelationRelationId && deprec->objsubid == 0 && deprec->deptype == DEPENDENCY_INTERNAL) {
relkind = get_rel_relkind(deprec->objid);
if (relkind == RELKIND_INDEX || relkind == RELKIND_GLOBAL_INDEX) {
indexId = deprec->objid;
break;
}
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return indexId;
}
* get_index_constraint
* Given the OID of an index, return the OID of the owning unique or
* primary-key constraint, or InvalidOid if no such constraint.
*/
Oid get_index_constraint(Oid indexId)
{
Oid constraintId = InvalidOid;
Relation depRel = NULL;
ScanKeyData key[3];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(indexId));
ScanKeyInit(&key[2], Anum_pg_depend_objsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(0));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, 3, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
Form_pg_depend deprec = (Form_pg_depend)GETSTRUCT(tup);
* We assume any internal dependency on a constraint must be what we
* are looking for.
*/
if (deprec->refclassid == ConstraintRelationId && deprec->refobjsubid == 0 &&
deprec->deptype == DEPENDENCY_INTERNAL) {
constraintId = deprec->refobjid;
break;
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return constraintId;
}
* get_index_ref_constraints
* Given the OID of an index, return the OID of all foreign key
* constraints which reference the index.
*/
List* get_index_ref_constraints(Oid indexId)
{
List* result = NULL;
Relation depRel = NULL;
ScanKeyData key[3];
SysScanDesc scan = NULL;
HeapTuple tup = NULL;
depRel = heap_open(DependRelationId,AccessShareLock);
ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(indexId));
ScanKeyInit(&key[2], Anum_pg_depend_refobjsubid, BTEqualStrategyNumber, F_INT4EQ, Int32GetDatum(0));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, 3, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
* We assume any normal dependency from a constraint must be what we
* are looking for.
*/
if (deprec->classid == ConstraintRelationId && deprec->objsubid == 0 &&
deprec->deptype == DEPENDENCY_NORMAL)
{
result = lappend_oid(result, deprec->objid);
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return result;
}
long DeleteTypesDenpendOnPackage(Oid classId, Oid objectId, bool isSpec)
{
long count = 0;
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
ObjectAddresses* objects = new_object_addresses();
ObjectAddress address;
const int keyNumber = 2;
char* typName = NULL;
bool isPkgDepTyp = false;
Form_pg_depend depTuple = NULL;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, keyNumber, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
depTuple = (Form_pg_depend)GETSTRUCT(tup);
isPkgDepTyp = (depTuple->deptype == DEPENDENCY_AUTO) &&
(depTuple->classid == TypeRelationId || depTuple->classid == PgSynonymRelationId);
if (!isPkgDepTyp) {
continue;
}
if (!isSpec) {
if (depTuple->classid == TypeRelationId) {
typName = get_typename(depTuple->objid);
} else {
typName = pstrdup(GetQualifiedSynonymName(depTuple->objid, false));
}
if (typName[0] != '$') {
pfree(typName);
continue;
}
pfree(typName);
}
address.classId = depTuple->classid;
address.objectId = depTuple->objid;
address.objectSubId = 0;
add_exact_object_address(&address, objects);
count++;
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
CommandCounterIncrement();
performMultipleDeletions(objects, DROP_CASCADE, PERFORM_DELETION_INTERNAL, true);
return count;
}
bool IsPackageDependType(Oid typOid, Oid pkgOid, bool isRefCur)
{
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
const int keyNumber = 2;
bool isFind = false;
depRel = heap_open(DependRelationId, RowExclusiveLock);
if (isRefCur) {
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(PgSynonymRelationId));
} else {
ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(TypeRelationId));
}
ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(typOid));
scan = systable_beginscan(depRel, DependDependerIndexId, true, NULL, keyNumber, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
if (((Form_pg_depend)GETSTRUCT(tup))->deptype == DEPENDENCY_AUTO) {
if (OidIsValid(pkgOid)) {
if (((Form_pg_depend)GETSTRUCT(tup))->refobjid == pkgOid) {
isFind = true;
break;
}
} else {
if (((Form_pg_depend)GETSTRUCT(tup))->refclassid == PackageRelationId
|| ((Form_pg_depend)GETSTRUCT(tup))->refclassid == ProcedureRelationId) {
isFind = true;
break;
}
}
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
return isFind;
}
* when rebuild function, delete subprograms which dependent on it.
*/
long DeleteSubprogramDenpendOnProcedure(Oid classId, Oid objectId, bool is_delete)
{
long count = 0;
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
ObjectAddresses* objects = new_object_addresses();
ObjectAddress address;
const int keyNumber = 2;
bool isPkgDepTyp = false;
Form_pg_depend depTuple = NULL;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, keyNumber, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
depTuple = (Form_pg_depend)GETSTRUCT(tup);
isPkgDepTyp = (depTuple->deptype == DEPENDENCY_NORMAL) && depTuple->classid == ProcedureRelationId;
if (!isPkgDepTyp) {
continue;
}
* only delete subprogram.
*/
if (!OidIsValid(GetProprocoidByOid(depTuple->objid))) {
continue;
}
address.classId = depTuple->classid;
address.objectId = depTuple->objid;
address.objectSubId = 0;
add_exact_object_address(&address, objects);
count++;
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
if (is_delete) {
CommandCounterIncrement();
performMultipleDeletions(objects, DROP_CASCADE, PERFORM_DELETION_INTERNAL, true);
}
return count;
}
void DeletePgDependObject(const ObjectAddress* object, const ObjectAddress* ref_object)
{
int keyNum = 0;
ScanKeyData key[2];
ScanKeyInit(&key[keyNum++], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->classId));
ScanKeyInit(&key[keyNum++], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId));
Relation relation = heap_open(DependRelationId, RowExclusiveLock);
SysScanDesc scan = systable_beginscan(relation, DependDependerIndexId, true, NULL, keyNum, key);
bool is_null = false;
HeapTuple tuple;
while (HeapTupleIsValid(tuple = systable_getnext(scan))) {
Datum refclassid_datum = heap_getattr(tuple, Anum_pg_depend_refclassid,
RelationGetDescr(relation), &is_null);
Datum refobjid_datum = heap_getattr(tuple, Anum_pg_depend_refobjid,
RelationGetDescr(relation), &is_null);
if (ref_object->classId == DatumGetObjectId(refclassid_datum) &&
ref_object->objectId == DatumGetObjectId(refobjid_datum)) {
simple_heap_delete(relation, &tuple->t_self);
systable_endscan(scan);
heap_close(relation, RowExclusiveLock);
CommandCounterIncrement();
return;
}
}
systable_endscan(scan);
heap_close(relation, RowExclusiveLock);
}
void fillDepsrcIfNeeded(const ObjectAddress* origObject)
{
Relation depRel;
SysScanDesc scan;
const int keyNumber = 2;
ScanKeyData key[keyNumber];
HeapTuple tup;
Form_pg_depend depTuple = NULL;
bool isnull = false;
Datum values[Natts_pg_depend];
bool nulls[Natts_pg_depend] = {false};
bool replaces[Natts_pg_depend] = {false};
Assert(getObjectClass(origObject) == OCLASS_PROC);
char* fullName = get_func_full_name(origObject->objectId);
if (fullName == NULL) {
return;
}
values[Anum_pg_depend_depsrc -1] = CStringGetTextDatum(fullName);
replaces[Anum_pg_depend_depsrc -1] = true;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0], Anum_pg_depend_refclassid, BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(origObject->classId));
ScanKeyInit(&key[1], Anum_pg_depend_refobjid, BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(origObject->objectId));
scan = systable_beginscan(depRel, DependReferenceIndexId, true, NULL, keyNumber, key);
while (HeapTupleIsValid(tup = systable_getnext(scan))) {
depTuple = (Form_pg_depend)GETSTRUCT(tup);
Datum depsrc = heap_getattr(tup, Anum_pg_depend_depsrc, RelationGetDescr(depRel), &isnull);
if (!isnull) {
continue;
}
HeapTuple new_tuple = heap_modify_tuple(tup, RelationGetDescr(depRel), values, nulls, replaces);
(void)simple_heap_update(depRel, &new_tuple->t_self, new_tuple, true);
CatalogUpdateIndexes(depRel, new_tuple);
heap_freetuple_ext(new_tuple);
}
pfree(fullName);
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
CommandCounterIncrement();
}