1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-30 06:01:21 +03:00

Eliminate cache lookup errors in SQL functions for object addresses

When using the following functions, users could see various types of
errors of the type "cache lookup failed for OID XXX" with elog(), that
can only be used for internal errors:
* pg_describe_object()
* pg_identify_object()
* pg_identify_object_as_address()

The set of APIs managing object addresses for all object types are made
smarter by gaining a new argument "missing_ok" that allows any caller to
control if an error is raised or not on an undefined object.  The SQL
functions listed above are changed to handle the case where an object is
missing.

Regression tests are added for all object types for the cases where
these are undefined.  Before this commit, these cases failed with cache
lookup errors, and now they basically return NULL (minus the name of the
object type requested).

Author: Michael Paquier
Reviewed-by: Aleksander Alekseev, Dmitry Dolgov, Daniel Gustafsson,
Álvaro Herrera, Kyotaro Horiguchi
Discussion: https://postgr.es/m/CAB7nPqSZxrSmdHK-rny7z8mi=EAFXJ5J-0RbzDw6aus=wB5azQ@mail.gmail.com
This commit is contained in:
Michael Paquier
2020-07-15 09:03:10 +09:00
parent 689696c711
commit 2a10fdc430
19 changed files with 996 additions and 332 deletions

View File

@@ -743,8 +743,8 @@ findDependentObjects(const ObjectAddress *object,
if (!object_address_present_add_flags(object, objflags,
targetObjects))
elog(ERROR, "deletion of owning object %s failed to delete %s",
getObjectDescription(&otherObject),
getObjectDescription(object));
getObjectDescription(&otherObject, false),
getObjectDescription(object, false));
/* And we're done here. */
return;
@@ -790,11 +790,11 @@ findDependentObjects(const ObjectAddress *object,
* the depender fields...
*/
elog(ERROR, "incorrect use of PIN dependency with %s",
getObjectDescription(object));
getObjectDescription(object, false));
break;
default:
elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object));
foundDep->deptype, getObjectDescription(object, false));
break;
}
}
@@ -812,14 +812,14 @@ findDependentObjects(const ObjectAddress *object,
char *otherObjDesc;
if (OidIsValid(partitionObject.classId))
otherObjDesc = getObjectDescription(&partitionObject);
otherObjDesc = getObjectDescription(&partitionObject, false);
else
otherObjDesc = getObjectDescription(&owningObject);
otherObjDesc = getObjectDescription(&owningObject, false);
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it",
getObjectDescription(object), otherObjDesc),
getObjectDescription(object, false), otherObjDesc),
errhint("You can drop %s instead.", otherObjDesc)));
}
@@ -929,12 +929,12 @@ findDependentObjects(const ObjectAddress *object,
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because it is required by the database system",
getObjectDescription(object))));
getObjectDescription(object, false))));
subflags = 0; /* keep compiler quiet */
break;
default:
elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object));
foundDep->deptype, getObjectDescription(object, false));
subflags = 0; /* keep compiler quiet */
break;
}
@@ -1052,12 +1052,13 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
!(extra->flags & DEPFLAG_PARTITION))
{
const ObjectAddress *object = &targetObjects->refs[i];
char *otherObjDesc = getObjectDescription(&extra->dependee);
char *otherObjDesc = getObjectDescription(&extra->dependee,
false);
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it",
getObjectDescription(object), otherObjDesc),
getObjectDescription(object, false), otherObjDesc),
errhint("You can drop %s instead.", otherObjDesc)));
}
}
@@ -1105,7 +1106,7 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
if (extra->flags & DEPFLAG_SUBOBJECT)
continue;
objDesc = getObjectDescription(obj);
objDesc = getObjectDescription(obj, false);
/*
* If, at any stage of the recursive search, we reached the object via
@@ -1129,7 +1130,8 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
}
else if (behavior == DROP_RESTRICT)
{
char *otherDesc = getObjectDescription(&extra->dependee);
char *otherDesc = getObjectDescription(&extra->dependee,
false);
if (numReportedClient < MAX_REPORTED_DEPS)
{
@@ -1187,7 +1189,7 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because other objects depend on it",
getObjectDescription(origObject)),
getObjectDescription(origObject, false)),
errdetail("%s", clientdetail.data),
errdetail_log("%s", logdetail.data),
errhint("Use DROP ... CASCADE to drop the dependent objects too.")));

File diff suppressed because it is too large Load Diff

View File

@@ -160,7 +160,7 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(object),
getObjectDescription(object, false),
get_extension_name(oldext))));
}
}
@@ -536,7 +536,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot remove dependency on %s because it is a system object",
getObjectDescription(&objAddr))));
getObjectDescription(&objAddr, false))));
/*
* We can handle adding a dependency on something pinned, though, since

View File

@@ -638,7 +638,7 @@ checkSharedDependencies(Oid classId, Oid objectId,
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because it is required by the database system",
getObjectDescription(&object))));
getObjectDescription(&object, false))));
}
object.classId = sdepForm->classid;
@@ -1147,7 +1147,7 @@ storeObjectDescription(StringInfo descs,
SharedDependencyType deptype,
int count)
{
char *objdesc = getObjectDescription(object);
char *objdesc = getObjectDescription(object, false);
/* separate entries with a newline */
if (descs->len != 0)
@@ -1283,7 +1283,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop objects owned by %s because they are "
"required by the database system",
getObjectDescription(&obj))));
getObjectDescription(&obj, false))));
}
ScanKeyInit(&key[0],
@@ -1429,7 +1429,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system",
getObjectDescription(&obj))));
getObjectDescription(&obj, false))));
/*
* There's no need to tell the whole truth, which is that we

View File

@@ -1267,10 +1267,11 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
/* object identity, objname and objargs */
obj->objidentity =
getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs);
getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
false);
/* object type */
obj->objecttype = getObjectTypeDescription(&obj->address);
obj->objecttype = getObjectTypeDescription(&obj->address, false);
slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
@@ -1929,8 +1930,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
else if (cmd->type == SCT_AlterTSConfig)
addr = cmd->d.atscfg.address;
type = getObjectTypeDescription(&addr);
identity = getObjectIdentity(&addr);
type = getObjectTypeDescription(&addr, false);
identity = getObjectIdentity(&addr, false);
/*
* Obtain schema name, if any ("pg_temp" if a temp

View File

@@ -2919,7 +2919,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o
errmsg("extension \"%s\" does not support SET SCHEMA",
NameStr(extForm->extname)),
errdetail("%s is not in the extension's schema \"%s\"",
getObjectDescription(&dep),
getObjectDescription(&dep, false),
get_namespace_name(oldNspOid))));
}
@@ -3328,7 +3328,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(&object),
getObjectDescription(&object, false),
get_extension_name(oldExtension))));
/*
@@ -3368,7 +3368,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is not a member of extension \"%s\"",
getObjectDescription(&object),
getObjectDescription(&object, false),
stmt->extname)));
/*

View File

@@ -11304,7 +11304,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
{
/* Not expecting any other direct dependencies... */
elog(ERROR, "unexpected object depending on column: %s",
getObjectDescription(&foundObject));
getObjectDescription(&foundObject, false));
}
break;
}
@@ -11320,7 +11320,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot alter type of a column used by a view or rule"),
errdetail("%s depends on column \"%s\"",
getObjectDescription(&foundObject),
getObjectDescription(&foundObject, false),
colName)));
break;
@@ -11339,7 +11339,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot alter type of a column used in a trigger definition"),
errdetail("%s depends on column \"%s\"",
getObjectDescription(&foundObject),
getObjectDescription(&foundObject, false),
colName)));
break;
@@ -11357,7 +11357,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot alter type of a column used in a policy definition"),
errdetail("%s depends on column \"%s\"",
getObjectDescription(&foundObject),
getObjectDescription(&foundObject, false),
colName)));
break;
@@ -11418,7 +11418,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
* a column.
*/
elog(ERROR, "unexpected object depending on column: %s",
getObjectDescription(&foundObject));
getObjectDescription(&foundObject, false));
break;
/*
@@ -11474,7 +11474,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
foundDep->refobjsubid != 0)
)
elog(ERROR, "found unexpected dependency for column: %s",
getObjectDescription(&foundObject));
getObjectDescription(&foundObject, false));
CatalogTupleDelete(depRel, &depTup->t_self);
}

View File

@@ -418,7 +418,8 @@ format_procedure_extended(Oid procedure_oid, bits16 flags)
* This can be used to feed get_object_address.
*/
void
format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs,
bool missing_ok)
{
HeapTuple proctup;
Form_pg_proc procform;
@@ -428,7 +429,11 @@ format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
return;
}
procform = (Form_pg_proc) GETSTRUCT(proctup);
nargs = procform->pronargs;
@@ -856,15 +861,20 @@ format_operator_qualified(Oid operator_oid)
}
void
format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
format_operator_parts(Oid operator_oid, List **objnames, List **objargs,
bool missing_ok)
{
HeapTuple opertup;
Form_pg_operator oprForm;
opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
if (!HeapTupleIsValid(opertup))
elog(ERROR, "cache lookup failed for operator with OID %u",
operator_oid);
{
if (!missing_ok)
elog(ERROR, "cache lookup failed for operator with OID %u",
operator_oid);
return;
}
oprForm = (Form_pg_operator) GETSTRUCT(opertup);
*objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),