mirror of https://github.com/postgres/postgres
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:
parent
689696c711
commit
2a10fdc430
|
@ -142,7 +142,7 @@ sepgsql_database_drop(Oid databaseId)
|
|||
object.classId = DatabaseRelationId;
|
||||
object.objectId = databaseId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_DATABASE,
|
||||
|
@ -169,7 +169,7 @@ sepgsql_database_setattr(Oid databaseId)
|
|||
object.classId = DatabaseRelationId;
|
||||
object.objectId = databaseId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_DATABASE,
|
||||
|
@ -193,7 +193,7 @@ sepgsql_database_relabel(Oid databaseId, const char *seclabel)
|
|||
object.classId = DatabaseRelationId;
|
||||
object.objectId = databaseId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
/*
|
||||
* check db_database:{setattr relabelfrom} permission
|
||||
|
|
|
@ -179,7 +179,7 @@ check_relation_privileges(Oid relOid,
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
switch (relkind)
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
|
@ -256,7 +256,7 @@ check_relation_privileges(Oid relOid,
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = attnum;
|
||||
audit_name = getObjectDescription(&object);
|
||||
audit_name = getObjectDescription(&object, false);
|
||||
|
||||
result = sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_COLUMN,
|
||||
|
|
|
@ -355,7 +355,7 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
|
|||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_PROCEDURE,
|
||||
SEPG_DB_PROCEDURE__ENTRYPOINT,
|
||||
getObjectDescription(&object),
|
||||
getObjectDescription(&object, false),
|
||||
true);
|
||||
|
||||
sepgsql_avc_check_perms_label(stack->new_label,
|
||||
|
@ -523,7 +523,7 @@ sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("sepgsql provider does not support labels on %s",
|
||||
getObjectTypeDescription(object))));
|
||||
getObjectTypeDescription(object, false))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ sepgsql_proc_post_create(Oid functionId)
|
|||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
SEPG_DB_SCHEMA__ADD_NAME,
|
||||
getObjectIdentity(&object),
|
||||
getObjectIdentity(&object, false),
|
||||
true);
|
||||
|
||||
/*
|
||||
|
@ -114,7 +114,7 @@ sepgsql_proc_post_create(Oid functionId)
|
|||
object.classId = TypeRelationId;
|
||||
object.objectId = proForm->proargtypes.values[i];
|
||||
object.objectSubId = 0;
|
||||
appendStringInfoString(&audit_name, getObjectIdentity(&object));
|
||||
appendStringInfoString(&audit_name, getObjectIdentity(&object, false));
|
||||
}
|
||||
appendStringInfoChar(&audit_name, ')');
|
||||
|
||||
|
@ -164,7 +164,7 @@ sepgsql_proc_drop(Oid functionId)
|
|||
object.classId = NamespaceRelationId;
|
||||
object.objectId = get_func_namespace(functionId);
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
|
@ -179,7 +179,7 @@ sepgsql_proc_drop(Oid functionId)
|
|||
object.classId = ProcedureRelationId;
|
||||
object.objectId = functionId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_PROCEDURE,
|
||||
|
@ -204,7 +204,7 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel)
|
|||
object.classId = ProcedureRelationId;
|
||||
object.objectId = functionId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
/*
|
||||
* check db_procedure:{setattr relabelfrom} permission
|
||||
|
@ -292,7 +292,7 @@ sepgsql_proc_setattr(Oid functionId)
|
|||
object.classId = ProcedureRelationId;
|
||||
object.objectId = functionId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_PROCEDURE,
|
||||
|
@ -324,7 +324,7 @@ sepgsql_proc_execute(Oid functionId)
|
|||
object.classId = ProcedureRelationId;
|
||||
object.objectId = functionId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_PROCEDURE,
|
||||
SEPG_DB_PROCEDURE__EXECUTE,
|
||||
|
|
|
@ -102,7 +102,7 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
|
|||
|
||||
initStringInfo(&audit_name);
|
||||
appendStringInfo(&audit_name, "%s.%s",
|
||||
getObjectIdentity(&object),
|
||||
getObjectIdentity(&object, false),
|
||||
quote_identifier(NameStr(attForm->attname)));
|
||||
sepgsql_avc_check_perms_label(ncontext,
|
||||
SEPG_CLASS_DB_COLUMN,
|
||||
|
@ -146,7 +146,7 @@ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = attnum;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_COLUMN,
|
||||
|
@ -178,7 +178,7 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = attnum;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
/*
|
||||
* check db_column:{setattr relabelfrom} permission
|
||||
|
@ -222,7 +222,7 @@ sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = attnum;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_COLUMN,
|
||||
|
@ -288,7 +288,7 @@ sepgsql_relation_post_create(Oid relOid)
|
|||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
SEPG_DB_SCHEMA__ADD_NAME,
|
||||
getObjectIdentity(&object),
|
||||
getObjectIdentity(&object, false),
|
||||
true);
|
||||
|
||||
switch (classForm->relkind)
|
||||
|
@ -450,7 +450,7 @@ sepgsql_relation_drop(Oid relOid)
|
|||
object.classId = NamespaceRelationId;
|
||||
object.objectId = get_rel_namespace(relOid);
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
|
@ -472,7 +472,7 @@ sepgsql_relation_drop(Oid relOid)
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
tclass,
|
||||
|
@ -503,7 +503,7 @@ sepgsql_relation_drop(Oid relOid)
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = attForm->attnum;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_COLUMN,
|
||||
|
@ -584,7 +584,7 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
/*
|
||||
* check db_xxx:{setattr relabelfrom} permission
|
||||
|
@ -695,7 +695,7 @@ sepgsql_relation_setattr(Oid relOid)
|
|||
object.classId = RelationRelationId;
|
||||
object.objectId = relOid;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
tclass,
|
||||
|
|
|
@ -123,7 +123,7 @@ sepgsql_schema_drop(Oid namespaceId)
|
|||
object.classId = NamespaceRelationId;
|
||||
object.objectId = namespaceId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
|
@ -148,7 +148,7 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel)
|
|||
object.classId = NamespaceRelationId;
|
||||
object.objectId = namespaceId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
/*
|
||||
* check db_schema:{setattr relabelfrom} permission
|
||||
|
@ -186,7 +186,7 @@ check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation)
|
|||
object.classId = NamespaceRelationId;
|
||||
object.objectId = namespaceId;
|
||||
object.objectSubId = 0;
|
||||
audit_name = getObjectIdentity(&object);
|
||||
audit_name = getObjectIdentity(&object, false);
|
||||
|
||||
result = sepgsql_avc_check_perms(&object,
|
||||
SEPG_CLASS_DB_SCHEMA,
|
||||
|
|
|
@ -22826,7 +22826,8 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
|||
object). This description is intended to be human-readable, and might
|
||||
be translated, depending on server configuration. This is especially
|
||||
useful to determine the identity of an object referenced in the
|
||||
<structname>pg_depend</structname> catalog.
|
||||
<structname>pg_depend</structname> catalog. This function returns
|
||||
<literal>NULL</literal> values for undefined objects.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
|
@ -22858,7 +22859,8 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
|||
otherwise <literal>NULL</literal>;
|
||||
<parameter>identity</parameter> is the complete object identity, with
|
||||
the precise format depending on object type, and each name within the
|
||||
format being schema-qualified and quoted as necessary.
|
||||
format being schema-qualified and quoted as necessary. Undefined
|
||||
objects are identified with <literal>NULL</literal> values.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
|
@ -22915,6 +22917,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
|
|||
<parameter>objsubid</parameter> is the sub-object ID, or zero if none.
|
||||
This function is the inverse
|
||||
of <function>pg_identify_object_as_address</function>.
|
||||
Undefined objects are identified with <literal>NULL</literal> values.
|
||||
</para></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -70,14 +70,18 @@ extern bool get_object_namensp_unique(Oid class_id);
|
|||
extern HeapTuple get_catalog_object_by_oid(Relation catalog,
|
||||
AttrNumber oidcol, Oid objectId);
|
||||
|
||||
extern char *getObjectDescription(const ObjectAddress *object);
|
||||
extern char *getObjectDescription(const ObjectAddress *object,
|
||||
bool missing_ok);
|
||||
extern char *getObjectDescriptionOids(Oid classid, Oid objid);
|
||||
|
||||
extern int read_objtype_from_string(const char *objtype);
|
||||
extern char *getObjectTypeDescription(const ObjectAddress *object);
|
||||
extern char *getObjectIdentity(const ObjectAddress *address);
|
||||
extern char *getObjectTypeDescription(const ObjectAddress *object,
|
||||
bool missing_ok);
|
||||
extern char *getObjectIdentity(const ObjectAddress *address,
|
||||
bool missing_ok);
|
||||
extern char *getObjectIdentityParts(const ObjectAddress *address,
|
||||
List **objname, List **objargs);
|
||||
List **objname, List **objargs,
|
||||
bool missing_ok);
|
||||
extern struct ArrayType *strlist_to_textarray(List *list);
|
||||
|
||||
extern ObjectType get_relkind_objtype(char relkind);
|
||||
|
|
|
@ -29,10 +29,11 @@ extern List *stringToQualifiedNameList(const char *string);
|
|||
extern char *format_procedure(Oid procedure_oid);
|
||||
extern char *format_procedure_qualified(Oid procedure_oid);
|
||||
extern void format_procedure_parts(Oid operator_oid, List **objnames,
|
||||
List **objargs);
|
||||
List **objargs, bool missing_ok);
|
||||
|
||||
extern char *format_operator(Oid operator_oid);
|
||||
extern char *format_operator_qualified(Oid operator_oid);
|
||||
extern void format_operator_parts(Oid operator_oid, List **objnames,
|
||||
List **objargs);
|
||||
List **objargs, bool missing_ok);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -521,3 +521,103 @@ drop cascades to function trig()
|
|||
drop cascades to function proc(integer)
|
||||
DROP OWNED BY regress_addr_user;
|
||||
DROP USER regress_addr_user;
|
||||
--
|
||||
-- Checks for invalid objects
|
||||
--
|
||||
-- Make sure that NULL handling is correct.
|
||||
\pset null 'NULL'
|
||||
-- Temporarily disable fancy output, so as future additions never create
|
||||
-- a large amount of diffs.
|
||||
\a\t
|
||||
-- Keep this list in the same order as getObjectIdentityParts()
|
||||
-- in objectaddress.c.
|
||||
WITH objects (classid, objid, objsubid) AS (VALUES
|
||||
('pg_class'::regclass, 0, 0), -- no relation
|
||||
('pg_class'::regclass, 'pg_class'::regclass, 100), -- no column for relation
|
||||
('pg_proc'::regclass, 0, 0), -- no function
|
||||
('pg_type'::regclass, 0, 0), -- no type
|
||||
('pg_cast'::regclass, 0, 0), -- no cast
|
||||
('pg_collation'::regclass, 0, 0), -- no collation
|
||||
('pg_constraint'::regclass, 0, 0), -- no constraint
|
||||
('pg_conversion'::regclass, 0, 0), -- no conversion
|
||||
('pg_attrdef'::regclass, 0, 0), -- no default attribute
|
||||
('pg_language'::regclass, 0, 0), -- no language
|
||||
('pg_largeobject'::regclass, 0, 0), -- no large object, no error
|
||||
('pg_operator'::regclass, 0, 0), -- no operator
|
||||
('pg_opclass'::regclass, 0, 0), -- no opclass, no need to check for no access method
|
||||
('pg_opfamily'::regclass, 0, 0), -- no opfamily
|
||||
('pg_am'::regclass, 0, 0), -- no access method
|
||||
('pg_amop'::regclass, 0, 0), -- no AM operator
|
||||
('pg_amproc'::regclass, 0, 0), -- no AM proc
|
||||
('pg_rewrite'::regclass, 0, 0), -- no rewrite
|
||||
('pg_trigger'::regclass, 0, 0), -- no trigger
|
||||
('pg_namespace'::regclass, 0, 0), -- no schema
|
||||
('pg_statistic_ext'::regclass, 0, 0), -- no statistics
|
||||
('pg_ts_parser'::regclass, 0, 0), -- no TS parser
|
||||
('pg_ts_dict'::regclass, 0, 0), -- no TS dictionnary
|
||||
('pg_ts_template'::regclass, 0, 0), -- no TS template
|
||||
('pg_ts_config'::regclass, 0, 0), -- no TS configuration
|
||||
('pg_authid'::regclass, 0, 0), -- no role
|
||||
('pg_database'::regclass, 0, 0), -- no database
|
||||
('pg_tablespace'::regclass, 0, 0), -- no tablespace
|
||||
('pg_foreign_data_wrapper'::regclass, 0, 0), -- no FDW
|
||||
('pg_foreign_server'::regclass, 0, 0), -- no server
|
||||
('pg_user_mapping'::regclass, 0, 0), -- no user mapping
|
||||
('pg_default_acl'::regclass, 0, 0), -- no default ACL
|
||||
('pg_extension'::regclass, 0, 0), -- no extension
|
||||
('pg_event_trigger'::regclass, 0, 0), -- no event trigger
|
||||
('pg_policy'::regclass, 0, 0), -- no policy
|
||||
('pg_publication'::regclass, 0, 0), -- no publication
|
||||
('pg_publication_rel'::regclass, 0, 0), -- no publication relation
|
||||
('pg_subscription'::regclass, 0, 0), -- no subscription
|
||||
('pg_transform'::regclass, 0, 0) -- no transformation
|
||||
)
|
||||
SELECT ROW(pg_identify_object(objects.classid, objects.objid, objects.objsubid))
|
||||
AS ident,
|
||||
ROW(pg_identify_object_as_address(objects.classid, objects.objid, objects.objsubid))
|
||||
AS addr,
|
||||
pg_describe_object(objects.classid, objects.objid, objects.objsubid)
|
||||
AS descr
|
||||
FROM objects
|
||||
ORDER BY objects.classid, objects.objid, objects.objsubid;
|
||||
("(""default acl"",,,)")|("(""default acl"",,)")|NULL
|
||||
("(tablespace,,,)")|("(tablespace,,)")|NULL
|
||||
("(type,,,)")|("(type,,)")|NULL
|
||||
("(routine,,,)")|("(routine,,)")|NULL
|
||||
("(relation,,,)")|("(relation,,)")|NULL
|
||||
("(""table column"",,,)")|("(""table column"",,)")|NULL
|
||||
("(role,,,)")|("(role,,)")|NULL
|
||||
("(database,,,)")|("(database,,)")|NULL
|
||||
("(server,,,)")|("(server,,)")|NULL
|
||||
("(""user mapping"",,,)")|("(""user mapping"",,)")|NULL
|
||||
("(""foreign-data wrapper"",,,)")|("(""foreign-data wrapper"",,)")|NULL
|
||||
("(""access method"",,,)")|("(""access method"",,)")|NULL
|
||||
("(""operator of access method"",,,)")|("(""operator of access method"",,)")|NULL
|
||||
("(""function of access method"",,,)")|("(""function of access method"",,)")|NULL
|
||||
("(""default value"",,,)")|("(""default value"",,)")|NULL
|
||||
("(cast,,,)")|("(cast,,)")|NULL
|
||||
("(constraint,,,)")|("(constraint,,)")|NULL
|
||||
("(conversion,,,)")|("(conversion,,)")|NULL
|
||||
("(language,,,)")|("(language,,)")|NULL
|
||||
("(""large object"",,,)")|("(""large object"",,)")|NULL
|
||||
("(schema,,,)")|("(schema,,)")|NULL
|
||||
("(""operator class"",,,)")|("(""operator class"",,)")|NULL
|
||||
("(operator,,,)")|("(operator,,)")|NULL
|
||||
("(rule,,,)")|("(rule,,)")|NULL
|
||||
("(trigger,,,)")|("(trigger,,)")|NULL
|
||||
("(""operator family"",,,)")|("(""operator family"",,)")|NULL
|
||||
("(extension,,,)")|("(extension,,)")|NULL
|
||||
("(policy,,,)")|("(policy,,)")|NULL
|
||||
("(""statistics object"",,,)")|("(""statistics object"",,)")|NULL
|
||||
("(collation,,,)")|("(collation,,)")|NULL
|
||||
("(""event trigger"",,,)")|("(""event trigger"",,)")|NULL
|
||||
("(transform,,,)")|("(transform,,)")|NULL
|
||||
("(""text search dictionary"",,,)")|("(""text search dictionary"",,)")|NULL
|
||||
("(""text search parser"",,,)")|("(""text search parser"",,)")|NULL
|
||||
("(""text search configuration"",,,)")|("(""text search configuration"",,)")|NULL
|
||||
("(""text search template"",,,)")|("(""text search template"",,)")|NULL
|
||||
("(subscription,,,)")|("(subscription,,)")|NULL
|
||||
("(publication,,,)")|("(publication,,)")|NULL
|
||||
("(""publication relation"",,,)")|("(""publication relation"",,)")|NULL
|
||||
-- restore normal output mode
|
||||
\a\t
|
||||
|
|
|
@ -221,3 +221,67 @@ DROP SCHEMA addr_nsp CASCADE;
|
|||
|
||||
DROP OWNED BY regress_addr_user;
|
||||
DROP USER regress_addr_user;
|
||||
|
||||
--
|
||||
-- Checks for invalid objects
|
||||
--
|
||||
-- Make sure that NULL handling is correct.
|
||||
\pset null 'NULL'
|
||||
-- Temporarily disable fancy output, so as future additions never create
|
||||
-- a large amount of diffs.
|
||||
\a\t
|
||||
|
||||
-- Keep this list in the same order as getObjectIdentityParts()
|
||||
-- in objectaddress.c.
|
||||
WITH objects (classid, objid, objsubid) AS (VALUES
|
||||
('pg_class'::regclass, 0, 0), -- no relation
|
||||
('pg_class'::regclass, 'pg_class'::regclass, 100), -- no column for relation
|
||||
('pg_proc'::regclass, 0, 0), -- no function
|
||||
('pg_type'::regclass, 0, 0), -- no type
|
||||
('pg_cast'::regclass, 0, 0), -- no cast
|
||||
('pg_collation'::regclass, 0, 0), -- no collation
|
||||
('pg_constraint'::regclass, 0, 0), -- no constraint
|
||||
('pg_conversion'::regclass, 0, 0), -- no conversion
|
||||
('pg_attrdef'::regclass, 0, 0), -- no default attribute
|
||||
('pg_language'::regclass, 0, 0), -- no language
|
||||
('pg_largeobject'::regclass, 0, 0), -- no large object, no error
|
||||
('pg_operator'::regclass, 0, 0), -- no operator
|
||||
('pg_opclass'::regclass, 0, 0), -- no opclass, no need to check for no access method
|
||||
('pg_opfamily'::regclass, 0, 0), -- no opfamily
|
||||
('pg_am'::regclass, 0, 0), -- no access method
|
||||
('pg_amop'::regclass, 0, 0), -- no AM operator
|
||||
('pg_amproc'::regclass, 0, 0), -- no AM proc
|
||||
('pg_rewrite'::regclass, 0, 0), -- no rewrite
|
||||
('pg_trigger'::regclass, 0, 0), -- no trigger
|
||||
('pg_namespace'::regclass, 0, 0), -- no schema
|
||||
('pg_statistic_ext'::regclass, 0, 0), -- no statistics
|
||||
('pg_ts_parser'::regclass, 0, 0), -- no TS parser
|
||||
('pg_ts_dict'::regclass, 0, 0), -- no TS dictionnary
|
||||
('pg_ts_template'::regclass, 0, 0), -- no TS template
|
||||
('pg_ts_config'::regclass, 0, 0), -- no TS configuration
|
||||
('pg_authid'::regclass, 0, 0), -- no role
|
||||
('pg_database'::regclass, 0, 0), -- no database
|
||||
('pg_tablespace'::regclass, 0, 0), -- no tablespace
|
||||
('pg_foreign_data_wrapper'::regclass, 0, 0), -- no FDW
|
||||
('pg_foreign_server'::regclass, 0, 0), -- no server
|
||||
('pg_user_mapping'::regclass, 0, 0), -- no user mapping
|
||||
('pg_default_acl'::regclass, 0, 0), -- no default ACL
|
||||
('pg_extension'::regclass, 0, 0), -- no extension
|
||||
('pg_event_trigger'::regclass, 0, 0), -- no event trigger
|
||||
('pg_policy'::regclass, 0, 0), -- no policy
|
||||
('pg_publication'::regclass, 0, 0), -- no publication
|
||||
('pg_publication_rel'::regclass, 0, 0), -- no publication relation
|
||||
('pg_subscription'::regclass, 0, 0), -- no subscription
|
||||
('pg_transform'::regclass, 0, 0) -- no transformation
|
||||
)
|
||||
SELECT ROW(pg_identify_object(objects.classid, objects.objid, objects.objsubid))
|
||||
AS ident,
|
||||
ROW(pg_identify_object_as_address(objects.classid, objects.objid, objects.objsubid))
|
||||
AS addr,
|
||||
pg_describe_object(objects.classid, objects.objid, objects.objsubid)
|
||||
AS descr
|
||||
FROM objects
|
||||
ORDER BY objects.classid, objects.objid, objects.objsubid;
|
||||
|
||||
-- restore normal output mode
|
||||
\a\t
|
||||
|
|
Loading…
Reference in New Issue