Commit 2a10fdc4 authored by Michael Paquier's avatar Michael Paquier

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
parent 689696c7
...@@ -142,7 +142,7 @@ sepgsql_database_drop(Oid databaseId) ...@@ -142,7 +142,7 @@ sepgsql_database_drop(Oid databaseId)
object.classId = DatabaseRelationId; object.classId = DatabaseRelationId;
object.objectId = databaseId; object.objectId = databaseId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_DATABASE, SEPG_CLASS_DB_DATABASE,
...@@ -169,7 +169,7 @@ sepgsql_database_setattr(Oid databaseId) ...@@ -169,7 +169,7 @@ sepgsql_database_setattr(Oid databaseId)
object.classId = DatabaseRelationId; object.classId = DatabaseRelationId;
object.objectId = databaseId; object.objectId = databaseId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_DATABASE, SEPG_CLASS_DB_DATABASE,
...@@ -193,7 +193,7 @@ sepgsql_database_relabel(Oid databaseId, const char *seclabel) ...@@ -193,7 +193,7 @@ sepgsql_database_relabel(Oid databaseId, const char *seclabel)
object.classId = DatabaseRelationId; object.classId = DatabaseRelationId;
object.objectId = databaseId; object.objectId = databaseId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
/* /*
* check db_database:{setattr relabelfrom} permission * check db_database:{setattr relabelfrom} permission
......
...@@ -179,7 +179,7 @@ check_relation_privileges(Oid relOid, ...@@ -179,7 +179,7 @@ check_relation_privileges(Oid relOid,
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
switch (relkind) switch (relkind)
{ {
case RELKIND_RELATION: case RELKIND_RELATION:
...@@ -256,7 +256,7 @@ check_relation_privileges(Oid relOid, ...@@ -256,7 +256,7 @@ check_relation_privileges(Oid relOid,
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = attnum; object.objectSubId = attnum;
audit_name = getObjectDescription(&object); audit_name = getObjectDescription(&object, false);
result = sepgsql_avc_check_perms(&object, result = sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_COLUMN, SEPG_CLASS_DB_COLUMN,
......
...@@ -355,7 +355,7 @@ sepgsql_fmgr_hook(FmgrHookEventType event, ...@@ -355,7 +355,7 @@ sepgsql_fmgr_hook(FmgrHookEventType event,
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE, SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__ENTRYPOINT, SEPG_DB_PROCEDURE__ENTRYPOINT,
getObjectDescription(&object), getObjectDescription(&object, false),
true); true);
sepgsql_avc_check_perms_label(stack->new_label, sepgsql_avc_check_perms_label(stack->new_label,
...@@ -523,7 +523,7 @@ sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel) ...@@ -523,7 +523,7 @@ sepgsql_object_relabel(const ObjectAddress *object, const char *seclabel)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("sepgsql provider does not support labels on %s", errmsg("sepgsql provider does not support labels on %s",
getObjectTypeDescription(object)))); getObjectTypeDescription(object, false))));
break; break;
} }
} }
......
...@@ -80,7 +80,7 @@ sepgsql_proc_post_create(Oid functionId) ...@@ -80,7 +80,7 @@ sepgsql_proc_post_create(Oid functionId)
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA, SEPG_CLASS_DB_SCHEMA,
SEPG_DB_SCHEMA__ADD_NAME, SEPG_DB_SCHEMA__ADD_NAME,
getObjectIdentity(&object), getObjectIdentity(&object, false),
true); true);
/* /*
...@@ -114,7 +114,7 @@ sepgsql_proc_post_create(Oid functionId) ...@@ -114,7 +114,7 @@ sepgsql_proc_post_create(Oid functionId)
object.classId = TypeRelationId; object.classId = TypeRelationId;
object.objectId = proForm->proargtypes.values[i]; object.objectId = proForm->proargtypes.values[i];
object.objectSubId = 0; object.objectSubId = 0;
appendStringInfoString(&audit_name, getObjectIdentity(&object)); appendStringInfoString(&audit_name, getObjectIdentity(&object, false));
} }
appendStringInfoChar(&audit_name, ')'); appendStringInfoChar(&audit_name, ')');
...@@ -164,7 +164,7 @@ sepgsql_proc_drop(Oid functionId) ...@@ -164,7 +164,7 @@ sepgsql_proc_drop(Oid functionId)
object.classId = NamespaceRelationId; object.classId = NamespaceRelationId;
object.objectId = get_func_namespace(functionId); object.objectId = get_func_namespace(functionId);
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA, SEPG_CLASS_DB_SCHEMA,
...@@ -179,7 +179,7 @@ sepgsql_proc_drop(Oid functionId) ...@@ -179,7 +179,7 @@ sepgsql_proc_drop(Oid functionId)
object.classId = ProcedureRelationId; object.classId = ProcedureRelationId;
object.objectId = functionId; object.objectId = functionId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE, SEPG_CLASS_DB_PROCEDURE,
...@@ -204,7 +204,7 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel) ...@@ -204,7 +204,7 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel)
object.classId = ProcedureRelationId; object.classId = ProcedureRelationId;
object.objectId = functionId; object.objectId = functionId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
/* /*
* check db_procedure:{setattr relabelfrom} permission * check db_procedure:{setattr relabelfrom} permission
...@@ -292,7 +292,7 @@ sepgsql_proc_setattr(Oid functionId) ...@@ -292,7 +292,7 @@ sepgsql_proc_setattr(Oid functionId)
object.classId = ProcedureRelationId; object.classId = ProcedureRelationId;
object.objectId = functionId; object.objectId = functionId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE, SEPG_CLASS_DB_PROCEDURE,
...@@ -324,7 +324,7 @@ sepgsql_proc_execute(Oid functionId) ...@@ -324,7 +324,7 @@ sepgsql_proc_execute(Oid functionId)
object.classId = ProcedureRelationId; object.classId = ProcedureRelationId;
object.objectId = functionId; object.objectId = functionId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_PROCEDURE, SEPG_CLASS_DB_PROCEDURE,
SEPG_DB_PROCEDURE__EXECUTE, SEPG_DB_PROCEDURE__EXECUTE,
......
...@@ -102,7 +102,7 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum) ...@@ -102,7 +102,7 @@ sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum)
initStringInfo(&audit_name); initStringInfo(&audit_name);
appendStringInfo(&audit_name, "%s.%s", appendStringInfo(&audit_name, "%s.%s",
getObjectIdentity(&object), getObjectIdentity(&object, false),
quote_identifier(NameStr(attForm->attname))); quote_identifier(NameStr(attForm->attname)));
sepgsql_avc_check_perms_label(ncontext, sepgsql_avc_check_perms_label(ncontext,
SEPG_CLASS_DB_COLUMN, SEPG_CLASS_DB_COLUMN,
...@@ -146,7 +146,7 @@ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum) ...@@ -146,7 +146,7 @@ sepgsql_attribute_drop(Oid relOid, AttrNumber attnum)
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = attnum; object.objectSubId = attnum;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_COLUMN, SEPG_CLASS_DB_COLUMN,
...@@ -178,7 +178,7 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum, ...@@ -178,7 +178,7 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = attnum; object.objectSubId = attnum;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
/* /*
* check db_column:{setattr relabelfrom} permission * check db_column:{setattr relabelfrom} permission
...@@ -222,7 +222,7 @@ sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum) ...@@ -222,7 +222,7 @@ sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = attnum; object.objectSubId = attnum;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_COLUMN, SEPG_CLASS_DB_COLUMN,
...@@ -288,7 +288,7 @@ sepgsql_relation_post_create(Oid relOid) ...@@ -288,7 +288,7 @@ sepgsql_relation_post_create(Oid relOid)
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA, SEPG_CLASS_DB_SCHEMA,
SEPG_DB_SCHEMA__ADD_NAME, SEPG_DB_SCHEMA__ADD_NAME,
getObjectIdentity(&object), getObjectIdentity(&object, false),
true); true);
switch (classForm->relkind) switch (classForm->relkind)
...@@ -450,7 +450,7 @@ sepgsql_relation_drop(Oid relOid) ...@@ -450,7 +450,7 @@ sepgsql_relation_drop(Oid relOid)
object.classId = NamespaceRelationId; object.classId = NamespaceRelationId;
object.objectId = get_rel_namespace(relOid); object.objectId = get_rel_namespace(relOid);
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA, SEPG_CLASS_DB_SCHEMA,
...@@ -472,7 +472,7 @@ sepgsql_relation_drop(Oid relOid) ...@@ -472,7 +472,7 @@ sepgsql_relation_drop(Oid relOid)
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
tclass, tclass,
...@@ -503,7 +503,7 @@ sepgsql_relation_drop(Oid relOid) ...@@ -503,7 +503,7 @@ sepgsql_relation_drop(Oid relOid)
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = attForm->attnum; object.objectSubId = attForm->attnum;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_COLUMN, SEPG_CLASS_DB_COLUMN,
...@@ -584,7 +584,7 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel) ...@@ -584,7 +584,7 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
/* /*
* check db_xxx:{setattr relabelfrom} permission * check db_xxx:{setattr relabelfrom} permission
...@@ -695,7 +695,7 @@ sepgsql_relation_setattr(Oid relOid) ...@@ -695,7 +695,7 @@ sepgsql_relation_setattr(Oid relOid)
object.classId = RelationRelationId; object.classId = RelationRelationId;
object.objectId = relOid; object.objectId = relOid;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
tclass, tclass,
......
...@@ -123,7 +123,7 @@ sepgsql_schema_drop(Oid namespaceId) ...@@ -123,7 +123,7 @@ sepgsql_schema_drop(Oid namespaceId)
object.classId = NamespaceRelationId; object.classId = NamespaceRelationId;
object.objectId = namespaceId; object.objectId = namespaceId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
sepgsql_avc_check_perms(&object, sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA, SEPG_CLASS_DB_SCHEMA,
...@@ -148,7 +148,7 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel) ...@@ -148,7 +148,7 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel)
object.classId = NamespaceRelationId; object.classId = NamespaceRelationId;
object.objectId = namespaceId; object.objectId = namespaceId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
/* /*
* check db_schema:{setattr relabelfrom} permission * check db_schema:{setattr relabelfrom} permission
...@@ -186,7 +186,7 @@ check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation) ...@@ -186,7 +186,7 @@ check_schema_perms(Oid namespaceId, uint32 required, bool abort_on_violation)
object.classId = NamespaceRelationId; object.classId = NamespaceRelationId;
object.objectId = namespaceId; object.objectId = namespaceId;
object.objectSubId = 0; object.objectSubId = 0;
audit_name = getObjectIdentity(&object); audit_name = getObjectIdentity(&object, false);
result = sepgsql_avc_check_perms(&object, result = sepgsql_avc_check_perms(&object,
SEPG_CLASS_DB_SCHEMA, SEPG_CLASS_DB_SCHEMA,
......
...@@ -22826,7 +22826,8 @@ SELECT collation for ('foo' COLLATE "de_DE"); ...@@ -22826,7 +22826,8 @@ SELECT collation for ('foo' COLLATE "de_DE");
object). This description is intended to be human-readable, and might object). This description is intended to be human-readable, and might
be translated, depending on server configuration. This is especially be translated, depending on server configuration. This is especially
useful to determine the identity of an object referenced in the 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> </para></entry>
</row> </row>
...@@ -22858,7 +22859,8 @@ SELECT collation for ('foo' COLLATE "de_DE"); ...@@ -22858,7 +22859,8 @@ SELECT collation for ('foo' COLLATE "de_DE");
otherwise <literal>NULL</literal>; otherwise <literal>NULL</literal>;
<parameter>identity</parameter> is the complete object identity, with <parameter>identity</parameter> is the complete object identity, with
the precise format depending on object type, and each name within the 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> </para></entry>
</row> </row>
...@@ -22915,6 +22917,7 @@ SELECT collation for ('foo' COLLATE "de_DE"); ...@@ -22915,6 +22917,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
<parameter>objsubid</parameter> is the sub-object ID, or zero if none. <parameter>objsubid</parameter> is the sub-object ID, or zero if none.
This function is the inverse This function is the inverse
of <function>pg_identify_object_as_address</function>. of <function>pg_identify_object_as_address</function>.
Undefined objects are identified with <literal>NULL</literal> values.
</para></entry> </para></entry>
</row> </row>
</tbody> </tbody>
......
...@@ -743,8 +743,8 @@ findDependentObjects(const ObjectAddress *object, ...@@ -743,8 +743,8 @@ findDependentObjects(const ObjectAddress *object,
if (!object_address_present_add_flags(object, objflags, if (!object_address_present_add_flags(object, objflags,
targetObjects)) targetObjects))
elog(ERROR, "deletion of owning object %s failed to delete %s", elog(ERROR, "deletion of owning object %s failed to delete %s",
getObjectDescription(&otherObject), getObjectDescription(&otherObject, false),
getObjectDescription(object)); getObjectDescription(object, false));
/* And we're done here. */ /* And we're done here. */
return; return;
...@@ -790,11 +790,11 @@ findDependentObjects(const ObjectAddress *object, ...@@ -790,11 +790,11 @@ findDependentObjects(const ObjectAddress *object,
* the depender fields... * the depender fields...
*/ */
elog(ERROR, "incorrect use of PIN dependency with %s", elog(ERROR, "incorrect use of PIN dependency with %s",
getObjectDescription(object)); getObjectDescription(object, false));
break; break;
default: default:
elog(ERROR, "unrecognized dependency type '%c' for %s", elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object)); foundDep->deptype, getObjectDescription(object, false));
break; break;
} }
} }
...@@ -812,14 +812,14 @@ findDependentObjects(const ObjectAddress *object, ...@@ -812,14 +812,14 @@ findDependentObjects(const ObjectAddress *object,
char *otherObjDesc; char *otherObjDesc;
if (OidIsValid(partitionObject.classId)) if (OidIsValid(partitionObject.classId))
otherObjDesc = getObjectDescription(&partitionObject); otherObjDesc = getObjectDescription(&partitionObject, false);
else else
otherObjDesc = getObjectDescription(&owningObject); otherObjDesc = getObjectDescription(&owningObject, false);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it", errmsg("cannot drop %s because %s requires it",
getObjectDescription(object), otherObjDesc), getObjectDescription(object, false), otherObjDesc),
errhint("You can drop %s instead.", otherObjDesc))); errhint("You can drop %s instead.", otherObjDesc)));
} }
...@@ -929,12 +929,12 @@ findDependentObjects(const ObjectAddress *object, ...@@ -929,12 +929,12 @@ findDependentObjects(const ObjectAddress *object,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because it is required by the database system", errmsg("cannot drop %s because it is required by the database system",
getObjectDescription(object)))); getObjectDescription(object, false))));
subflags = 0; /* keep compiler quiet */ subflags = 0; /* keep compiler quiet */
break; break;
default: default:
elog(ERROR, "unrecognized dependency type '%c' for %s", elog(ERROR, "unrecognized dependency type '%c' for %s",
foundDep->deptype, getObjectDescription(object)); foundDep->deptype, getObjectDescription(object, false));
subflags = 0; /* keep compiler quiet */ subflags = 0; /* keep compiler quiet */
break; break;
} }
...@@ -1052,12 +1052,13 @@ reportDependentObjects(const ObjectAddresses *targetObjects, ...@@ -1052,12 +1052,13 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
!(extra->flags & DEPFLAG_PARTITION)) !(extra->flags & DEPFLAG_PARTITION))
{ {
const ObjectAddress *object = &targetObjects->refs[i]; const ObjectAddress *object = &targetObjects->refs[i];
char *otherObjDesc = getObjectDescription(&extra->dependee); char *otherObjDesc = getObjectDescription(&extra->dependee,
false);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it", errmsg("cannot drop %s because %s requires it",
getObjectDescription(object), otherObjDesc), getObjectDescription(object, false), otherObjDesc),
errhint("You can drop %s instead.", otherObjDesc))); errhint("You can drop %s instead.", otherObjDesc)));
} }
} }
...@@ -1105,7 +1106,7 @@ reportDependentObjects(const ObjectAddresses *targetObjects, ...@@ -1105,7 +1106,7 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
if (extra->flags & DEPFLAG_SUBOBJECT) if (extra->flags & DEPFLAG_SUBOBJECT)
continue; continue;
objDesc = getObjectDescription(obj); objDesc = getObjectDescription(obj, false);
/* /*
* If, at any stage of the recursive search, we reached the object via * If, at any stage of the recursive search, we reached the object via
...@@ -1129,7 +1130,8 @@ reportDependentObjects(const ObjectAddresses *targetObjects, ...@@ -1129,7 +1130,8 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
} }
else if (behavior == DROP_RESTRICT) else if (behavior == DROP_RESTRICT)
{ {
char *otherDesc = getObjectDescription(&extra->dependee); char *otherDesc = getObjectDescription(&extra->dependee,
false);
if (numReportedClient < MAX_REPORTED_DEPS) if (numReportedClient < MAX_REPORTED_DEPS)
{ {
...@@ -1187,7 +1189,7 @@ reportDependentObjects(const ObjectAddresses *targetObjects, ...@@ -1187,7 +1189,7 @@ reportDependentObjects(const ObjectAddresses *targetObjects,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because other objects depend on it", errmsg("cannot drop %s because other objects depend on it",
getObjectDescription(origObject)), getObjectDescription(origObject, false)),
errdetail("%s", clientdetail.data), errdetail("%s", clientdetail.data),
errdetail_log("%s", logdetail.data), errdetail_log("%s", logdetail.data),
errhint("Use DROP ... CASCADE to drop the dependent objects too."))); errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
......
...@@ -879,14 +879,20 @@ static ObjectAddress get_object_address_defacl(List *object, ...@@ -879,14 +879,20 @@ static ObjectAddress get_object_address_defacl(List *object,
bool missing_ok); bool missing_ok);
static const ObjectPropertyType *get_object_property_data(Oid class_id); static const ObjectPropertyType *get_object_property_data(Oid class_id);
static void getRelationDescription(StringInfo buffer, Oid relid); static void getRelationDescription(StringInfo buffer, Oid relid,
static void getOpFamilyDescription(StringInfo buffer, Oid opfid); bool missing_ok);
static void getOpFamilyDescription(StringInfo buffer, Oid opfid,
bool missing_ok);
static void getRelationTypeDescription(StringInfo buffer, Oid relid, static void getRelationTypeDescription(StringInfo buffer, Oid relid,
int32 objectSubId); int32 objectSubId, bool missing_ok);
static void getProcedureTypeDescription(StringInfo buffer, Oid procid); static void getProcedureTypeDescription(StringInfo buffer, Oid procid,
static void getConstraintTypeDescription(StringInfo buffer, Oid constroid); bool missing_ok);
static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object); static void getConstraintTypeDescription(StringInfo buffer, Oid constroid,
static void getRelationIdentity(StringInfo buffer, Oid relid, List **object); bool missing_ok);
static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
bool missing_ok);
static void getRelationIdentity(StringInfo buffer, Oid relid, List **object,
bool missing_ok);
/* /*
* Translate an object name and arguments (as passed by the parser) to an * Translate an object name and arguments (as passed by the parser) to an
...@@ -1759,7 +1765,7 @@ get_object_address_opf_member(ObjectType objtype, ...@@ -1759,7 +1765,7 @@ get_object_address_opf_member(ObjectType objtype,
membernum, membernum,
TypeNameToString(typenames[0]), TypeNameToString(typenames[0]),
TypeNameToString(typenames[1]), TypeNameToString(typenames[1]),
getObjectDescription(&famaddr)))); getObjectDescription(&famaddr, false))));
} }
else else
{ {
...@@ -1790,7 +1796,7 @@ get_object_address_opf_member(ObjectType objtype, ...@@ -1790,7 +1796,7 @@ get_object_address_opf_member(ObjectType objtype,
membernum, membernum,
TypeNameToString(typenames[0]), TypeNameToString(typenames[0]),
TypeNameToString(typenames[1]), TypeNameToString(typenames[1]),
getObjectDescription(&famaddr)))); getObjectDescription(&famaddr, false))));
} }
else else
{ {
...@@ -2844,10 +2850,11 @@ get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId) ...@@ -2844,10 +2850,11 @@ get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
/* /*
* getObjectDescription: build an object description for messages * getObjectDescription: build an object description for messages
* *
* The result is a palloc'd string. * The result is a palloc'd string. NULL is returned for an undefined
* object if missing_ok is true, else an error is generated.
*/ */
char * char *
getObjectDescription(const ObjectAddress *object) getObjectDescription(const ObjectAddress *object, bool missing_ok)
{ {
StringInfoData buffer; StringInfoData buffer;
...@@ -2857,33 +2864,49 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2857,33 +2864,49 @@ getObjectDescription(const ObjectAddress *object)
{ {
case OCLASS_CLASS: case OCLASS_CLASS:
if (object->objectSubId == 0) if (object->objectSubId == 0)
getRelationDescription(&buffer, object->objectId); getRelationDescription(&buffer, object->objectId, missing_ok);
else else
{ {
/* column, not whole relation */ /* column, not whole relation */
StringInfoData rel; StringInfoData rel;
char *attname = get_attname(object->objectId,
object->objectSubId,
missing_ok);
if (!attname)
break;
initStringInfo(&rel); initStringInfo(&rel);
getRelationDescription(&rel, object->objectId); getRelationDescription(&rel, object->objectId, missing_ok);
/* translator: second %s is, e.g., "table %s" */ /* translator: second %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("column %s of %s"), appendStringInfo(&buffer, _("column %s of %s"),
get_attname(object->objectId, attname, rel.data);
object->objectSubId,
false),
rel.data);
pfree(rel.data); pfree(rel.data);
} }
break; break;
case OCLASS_PROC: case OCLASS_PROC:
appendStringInfo(&buffer, _("function %s"), {
format_procedure(object->objectId)); bits16 flags = FORMAT_PROC_INVALID_AS_NULL;
break; char *proname = format_procedure_extended(object->objectId,
flags);
if (proname == NULL)
break;
appendStringInfo(&buffer, _("function %s"), proname);
break;
}
case OCLASS_TYPE: case OCLASS_TYPE:
appendStringInfo(&buffer, _("type %s"), {
format_type_be(object->objectId)); bits16 flags = FORMAT_TYPE_INVALID_AS_NULL;
break; char *typname = format_type_extended(object->objectId, -1,
flags);
if (typname == NULL)
break;
appendStringInfo(&buffer, _("type %s"), typname);
break;
}
case OCLASS_CAST: case OCLASS_CAST:
{ {
...@@ -2906,8 +2929,15 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2906,8 +2929,15 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(rcscan); tup = systable_getnext(rcscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for cast %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for cast %u",
object->objectId);
systable_endscan(rcscan);
table_close(castDesc, AccessShareLock);
break;
}
castForm = (Form_pg_cast) GETSTRUCT(tup); castForm = (Form_pg_cast) GETSTRUCT(tup);
...@@ -2929,8 +2959,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2929,8 +2959,13 @@ getObjectDescription(const ObjectAddress *object)
collTup = SearchSysCache1(COLLOID, collTup = SearchSysCache1(COLLOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(collTup)) if (!HeapTupleIsValid(collTup))
elog(ERROR, "cache lookup failed for collation %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for collation %u",
object->objectId);
break;
}
coll = (Form_pg_collation) GETSTRUCT(collTup); coll = (Form_pg_collation) GETSTRUCT(collTup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -2954,8 +2989,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2954,8 +2989,13 @@ getObjectDescription(const ObjectAddress *object)
conTup = SearchSysCache1(CONSTROID, conTup = SearchSysCache1(CONSTROID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(conTup)) if (!HeapTupleIsValid(conTup))
elog(ERROR, "cache lookup failed for constraint %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for constraint %u",
object->objectId);
break;
}
con = (Form_pg_constraint) GETSTRUCT(conTup); con = (Form_pg_constraint) GETSTRUCT(conTup);
if (OidIsValid(con->conrelid)) if (OidIsValid(con->conrelid))
...@@ -2963,7 +3003,7 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2963,7 +3003,7 @@ getObjectDescription(const ObjectAddress *object)
StringInfoData rel; StringInfoData rel;
initStringInfo(&rel); initStringInfo(&rel);
getRelationDescription(&rel, con->conrelid); getRelationDescription(&rel, con->conrelid, false);
/* translator: second %s is, e.g., "table %s" */ /* translator: second %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("constraint %s on %s"), appendStringInfo(&buffer, _("constraint %s on %s"),
NameStr(con->conname), rel.data); NameStr(con->conname), rel.data);
...@@ -2988,8 +3028,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -2988,8 +3028,13 @@ getObjectDescription(const ObjectAddress *object)
conTup = SearchSysCache1(CONVOID, conTup = SearchSysCache1(CONVOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(conTup)) if (!HeapTupleIsValid(conTup))
elog(ERROR, "cache lookup failed for conversion %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for conversion %u",
object->objectId);
break;
}
conv = (Form_pg_conversion) GETSTRUCT(conTup); conv = (Form_pg_conversion) GETSTRUCT(conTup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3027,8 +3072,15 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3027,8 +3072,15 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(adscan); tup = systable_getnext(adscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for attrdef %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for attrdef %u",
object->objectId);
systable_endscan(adscan);
table_close(attrdefDesc, AccessShareLock);
break;
}
attrdef = (Form_pg_attrdef) GETSTRUCT(tup); attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
...@@ -3038,7 +3090,7 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3038,7 +3090,7 @@ getObjectDescription(const ObjectAddress *object)
/* translator: %s is typically "column %s of table %s" */ /* translator: %s is typically "column %s of table %s" */
appendStringInfo(&buffer, _("default value for %s"), appendStringInfo(&buffer, _("default value for %s"),
getObjectDescription(&colobject)); getObjectDescription(&colobject, false));
systable_endscan(adscan); systable_endscan(adscan);
table_close(attrdefDesc, AccessShareLock); table_close(attrdefDesc, AccessShareLock);
...@@ -3046,19 +3098,35 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3046,19 +3098,35 @@ getObjectDescription(const ObjectAddress *object)
} }
case OCLASS_LANGUAGE: case OCLASS_LANGUAGE:
appendStringInfo(&buffer, _("language %s"), {
get_language_name(object->objectId, false)); char *langname = get_language_name(object->objectId,
break; missing_ok);
if (langname)
appendStringInfo(&buffer, _("language %s"),
get_language_name(object->objectId, false));
break;
}
case OCLASS_LARGEOBJECT: case OCLASS_LARGEOBJECT:
if (!LargeObjectExists(object->objectId))
break;
appendStringInfo(&buffer, _("large object %u"), appendStringInfo(&buffer, _("large object %u"),
object->objectId); object->objectId);
break; break;
case OCLASS_OPERATOR: case OCLASS_OPERATOR:
appendStringInfo(&buffer, _("operator %s"), {
format_operator(object->objectId)); bits16 flags = FORMAT_OPERATOR_INVALID_AS_NULL;
break; char *oprname = format_operator_extended(object->objectId,
flags);
if (oprname == NULL)
break;
appendStringInfo(&buffer, _("operator %s"), oprname);
break;
}
case OCLASS_OPCLASS: case OCLASS_OPCLASS:
{ {
...@@ -3071,8 +3139,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3071,8 +3139,13 @@ getObjectDescription(const ObjectAddress *object)
opcTup = SearchSysCache1(CLAOID, opcTup = SearchSysCache1(CLAOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(opcTup)) if (!HeapTupleIsValid(opcTup))
elog(ERROR, "cache lookup failed for opclass %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for opclass %u",
object->objectId);
break;
}
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup); opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
amTup = SearchSysCache1(AMOID, amTup = SearchSysCache1(AMOID,
...@@ -3099,7 +3172,7 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3099,7 +3172,7 @@ getObjectDescription(const ObjectAddress *object)
} }
case OCLASS_OPFAMILY: case OCLASS_OPFAMILY:
getOpFamilyDescription(&buffer, object->objectId); getOpFamilyDescription(&buffer, object->objectId, missing_ok);
break; break;
case OCLASS_AM: case OCLASS_AM:
...@@ -3109,8 +3182,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3109,8 +3182,13 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(AMOID, tup = SearchSysCache1(AMOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for access method %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for access method %u",
object->objectId);
break;
}
appendStringInfo(&buffer, _("access method %s"), appendStringInfo(&buffer, _("access method %s"),
NameStr(((Form_pg_am) GETSTRUCT(tup))->amname)); NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
ReleaseSysCache(tup); ReleaseSysCache(tup);
...@@ -3140,13 +3218,20 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3140,13 +3218,20 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(amscan); tup = systable_getnext(amscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amop entry %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for amop entry %u",
object->objectId);
systable_endscan(amscan);
table_close(amopDesc, AccessShareLock);
break;
}
amopForm = (Form_pg_amop) GETSTRUCT(tup); amopForm = (Form_pg_amop) GETSTRUCT(tup);
initStringInfo(&opfam); initStringInfo(&opfam);
getOpFamilyDescription(&opfam, amopForm->amopfamily); getOpFamilyDescription(&opfam, amopForm->amopfamily, false);
/*------ /*------
translator: %d is the operator strategy (a number), the translator: %d is the operator strategy (a number), the
...@@ -3190,13 +3275,20 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3190,13 +3275,20 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(amscan); tup = systable_getnext(amscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amproc entry %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for amproc entry %u",
object->objectId);
systable_endscan(amscan);
table_close(amprocDesc, AccessShareLock);
break;
}
amprocForm = (Form_pg_amproc) GETSTRUCT(tup); amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
initStringInfo(&opfam); initStringInfo(&opfam);
getOpFamilyDescription(&opfam, amprocForm->amprocfamily); getOpFamilyDescription(&opfam, amprocForm->amprocfamily, false);
/*------ /*------
translator: %d is the function number, the first two %s's translator: %d is the function number, the first two %s's
...@@ -3239,12 +3331,20 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3239,12 +3331,20 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(rcscan); tup = systable_getnext(rcscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for rule %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for rule %u",
object->objectId);
systable_endscan(rcscan);
table_close(ruleDesc, AccessShareLock);
break;
}
rule = (Form_pg_rewrite) GETSTRUCT(tup); rule = (Form_pg_rewrite) GETSTRUCT(tup);
initStringInfo(&rel); initStringInfo(&rel);
getRelationDescription(&rel, rule->ev_class); getRelationDescription(&rel, rule->ev_class, false);
/* translator: second %s is, e.g., "table %s" */ /* translator: second %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("rule %s on %s"), appendStringInfo(&buffer, _("rule %s on %s"),
...@@ -3277,12 +3377,20 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3277,12 +3377,20 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(tgscan); tup = systable_getnext(tgscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for trigger %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for trigger %u",
object->objectId);
systable_endscan(tgscan);
table_close(trigDesc, AccessShareLock);
break;
}
trig = (Form_pg_trigger) GETSTRUCT(tup); trig = (Form_pg_trigger) GETSTRUCT(tup);
initStringInfo(&rel); initStringInfo(&rel);
getRelationDescription(&rel, trig->tgrelid); getRelationDescription(&rel, trig->tgrelid, false);
/* translator: second %s is, e.g., "table %s" */ /* translator: second %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("trigger %s on %s"), appendStringInfo(&buffer, _("trigger %s on %s"),
...@@ -3299,8 +3407,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3299,8 +3407,12 @@ getObjectDescription(const ObjectAddress *object)
nspname = get_namespace_name(object->objectId); nspname = get_namespace_name(object->objectId);
if (!nspname) if (!nspname)
elog(ERROR, "cache lookup failed for namespace %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for namespace %u",
object->objectId);
break;
}
appendStringInfo(&buffer, _("schema %s"), nspname); appendStringInfo(&buffer, _("schema %s"), nspname);
break; break;
} }
...@@ -3314,8 +3426,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3314,8 +3426,13 @@ getObjectDescription(const ObjectAddress *object)
stxTup = SearchSysCache1(STATEXTOID, stxTup = SearchSysCache1(STATEXTOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(stxTup)) if (!HeapTupleIsValid(stxTup))
elog(ERROR, "could not find tuple for statistics object %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for statistics object %u",
object->objectId);
break;
}
stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup); stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3341,8 +3458,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3341,8 +3458,12 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(TSPARSEROID, tup = SearchSysCache1(TSPARSEROID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search parser %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search parser %u",
object->objectId);
break;
}
prsForm = (Form_pg_ts_parser) GETSTRUCT(tup); prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3367,8 +3488,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3367,8 +3488,13 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(TSDICTOID, tup = SearchSysCache1(TSDICTOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search dictionary %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search dictionary %u",
object->objectId);
break;
}
dictForm = (Form_pg_ts_dict) GETSTRUCT(tup); dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3393,8 +3519,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3393,8 +3519,13 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(TSTEMPLATEOID, tup = SearchSysCache1(TSTEMPLATEOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search template %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search template %u",
object->objectId);
break;
}
tmplForm = (Form_pg_ts_template) GETSTRUCT(tup); tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3419,8 +3550,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3419,8 +3550,13 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(TSCONFIGOID, tup = SearchSysCache1(TSCONFIGOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search configuration %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search configuration %u",
object->objectId);
break;
}
cfgForm = (Form_pg_ts_config) GETSTRUCT(tup); cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3438,8 +3574,11 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3438,8 +3574,11 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_ROLE: case OCLASS_ROLE:
{ {
appendStringInfo(&buffer, _("role %s"), char *username = GetUserNameFromId(object->objectId,
GetUserNameFromId(object->objectId, false)); missing_ok);
if (username)
appendStringInfo(&buffer, _("role %s"), username);
break; break;
} }
...@@ -3449,8 +3588,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3449,8 +3588,12 @@ getObjectDescription(const ObjectAddress *object)
datname = get_database_name(object->objectId); datname = get_database_name(object->objectId);
if (!datname) if (!datname)
elog(ERROR, "cache lookup failed for database %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for database %u",
object->objectId);
break;
}
appendStringInfo(&buffer, _("database %s"), datname); appendStringInfo(&buffer, _("database %s"), datname);
break; break;
} }
...@@ -3461,8 +3604,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3461,8 +3604,12 @@ getObjectDescription(const ObjectAddress *object)
tblspace = get_tablespace_name(object->objectId); tblspace = get_tablespace_name(object->objectId);
if (!tblspace) if (!tblspace)
elog(ERROR, "cache lookup failed for tablespace %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for tablespace %u",
object->objectId);
break;
}
appendStringInfo(&buffer, _("tablespace %s"), tblspace); appendStringInfo(&buffer, _("tablespace %s"), tblspace);
break; break;
} }
...@@ -3471,8 +3618,10 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3471,8 +3618,10 @@ getObjectDescription(const ObjectAddress *object)
{ {
ForeignDataWrapper *fdw; ForeignDataWrapper *fdw;
fdw = GetForeignDataWrapper(object->objectId); fdw = GetForeignDataWrapperExtended(object->objectId,
appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname); missing_ok);
if (fdw)
appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
break; break;
} }
...@@ -3480,8 +3629,9 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3480,8 +3629,9 @@ getObjectDescription(const ObjectAddress *object)
{ {
ForeignServer *srv; ForeignServer *srv;
srv = GetForeignServer(object->objectId); srv = GetForeignServerExtended(object->objectId, missing_ok);
appendStringInfo(&buffer, _("server %s"), srv->servername); if (srv)
appendStringInfo(&buffer, _("server %s"), srv->servername);
break; break;
} }
...@@ -3496,8 +3646,13 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3496,8 +3646,13 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(USERMAPPINGOID, tup = SearchSysCache1(USERMAPPINGOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for user mapping %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for user mapping %u",
object->objectId);
break;
}
umform = (Form_pg_user_mapping) GETSTRUCT(tup); umform = (Form_pg_user_mapping) GETSTRUCT(tup);
useid = umform->umuser; useid = umform->umuser;
srv = GetForeignServer(umform->umserver); srv = GetForeignServer(umform->umserver);
...@@ -3537,8 +3692,15 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3537,8 +3692,15 @@ getObjectDescription(const ObjectAddress *object)
tup = systable_getnext(rcscan); tup = systable_getnext(rcscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for default ACL %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for default ACL %u",
object->objectId);
systable_endscan(rcscan);
table_close(defaclrel, AccessShareLock);
break;
}
defacl = (Form_pg_default_acl) GETSTRUCT(tup); defacl = (Form_pg_default_acl) GETSTRUCT(tup);
...@@ -3621,8 +3783,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3621,8 +3783,12 @@ getObjectDescription(const ObjectAddress *object)
extname = get_extension_name(object->objectId); extname = get_extension_name(object->objectId);
if (!extname) if (!extname)
elog(ERROR, "cache lookup failed for extension %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for extension %u",
object->objectId);
break;
}
appendStringInfo(&buffer, _("extension %s"), extname); appendStringInfo(&buffer, _("extension %s"), extname);
break; break;
} }
...@@ -3634,8 +3800,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3634,8 +3800,12 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(EVENTTRIGGEROID, tup = SearchSysCache1(EVENTTRIGGEROID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for event trigger %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for event trigger %u",
object->objectId);
break;
}
appendStringInfo(&buffer, _("event trigger %s"), appendStringInfo(&buffer, _("event trigger %s"),
NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname)); NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
ReleaseSysCache(tup); ReleaseSysCache(tup);
...@@ -3664,12 +3834,20 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3664,12 +3834,20 @@ getObjectDescription(const ObjectAddress *object)
tuple = systable_getnext(sscan); tuple = systable_getnext(sscan);
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "could not find tuple for policy %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for policy %u",
object->objectId);
systable_endscan(sscan);
table_close(policy_rel, AccessShareLock);
break;
}
form_policy = (Form_pg_policy) GETSTRUCT(tuple); form_policy = (Form_pg_policy) GETSTRUCT(tuple);
initStringInfo(&rel); initStringInfo(&rel);
getRelationDescription(&rel, form_policy->polrelid); getRelationDescription(&rel, form_policy->polrelid, false);
/* translator: second %s is, e.g., "table %s" */ /* translator: second %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("policy %s on %s"), appendStringInfo(&buffer, _("policy %s on %s"),
...@@ -3682,9 +3860,10 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3682,9 +3860,10 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_PUBLICATION: case OCLASS_PUBLICATION:
{ {
appendStringInfo(&buffer, _("publication %s"), char *pubname = get_publication_name(object->objectId,
get_publication_name(object->objectId, missing_ok);
false)); if (pubname)
appendStringInfo(&buffer, _("publication %s"), pubname);
break; break;
} }
...@@ -3698,14 +3877,18 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3698,14 +3877,18 @@ getObjectDescription(const ObjectAddress *object)
tup = SearchSysCache1(PUBLICATIONREL, tup = SearchSysCache1(PUBLICATIONREL,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for publication table %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for publication table %u",
object->objectId);
break;
}
prform = (Form_pg_publication_rel) GETSTRUCT(tup); prform = (Form_pg_publication_rel) GETSTRUCT(tup);
pubname = get_publication_name(prform->prpubid, false); pubname = get_publication_name(prform->prpubid, false);
initStringInfo(&rel); initStringInfo(&rel);
getRelationDescription(&rel, prform->prrelid); getRelationDescription(&rel, prform->prrelid, false);
/* translator: first %s is, e.g., "table %s" */ /* translator: first %s is, e.g., "table %s" */
appendStringInfo(&buffer, _("publication of %s in publication %s"), appendStringInfo(&buffer, _("publication of %s in publication %s"),
...@@ -3717,9 +3900,10 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3717,9 +3900,10 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_SUBSCRIPTION: case OCLASS_SUBSCRIPTION:
{ {
appendStringInfo(&buffer, _("subscription %s"), char *subname = get_subscription_name(object->objectId,
get_subscription_name(object->objectId, missing_ok);
false)); if (subname)
appendStringInfo(&buffer, _("subscription %s"), subname);
break; break;
} }
...@@ -3731,8 +3915,12 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3731,8 +3915,12 @@ getObjectDescription(const ObjectAddress *object)
trfTup = SearchSysCache1(TRFOID, trfTup = SearchSysCache1(TRFOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(trfTup)) if (!HeapTupleIsValid(trfTup))
elog(ERROR, "could not find tuple for transform %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for transform %u",
object->objectId);
break;
}
trfForm = (Form_pg_transform) GETSTRUCT(trfTup); trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
...@@ -3750,6 +3938,10 @@ getObjectDescription(const ObjectAddress *object) ...@@ -3750,6 +3938,10 @@ getObjectDescription(const ObjectAddress *object)
*/ */
} }
/* an empty buffer is equivalent to no object found */
if (buffer.len == 0)
return NULL;
return buffer.data; return buffer.data;
} }
...@@ -3765,7 +3957,7 @@ getObjectDescriptionOids(Oid classid, Oid objid) ...@@ -3765,7 +3957,7 @@ getObjectDescriptionOids(Oid classid, Oid objid)
address.objectId = objid; address.objectId = objid;
address.objectSubId = 0; address.objectSubId = 0;
return getObjectDescription(&address); return getObjectDescription(&address, false);
} }
/* /*
...@@ -3774,7 +3966,7 @@ getObjectDescriptionOids(Oid classid, Oid objid) ...@@ -3774,7 +3966,7 @@ getObjectDescriptionOids(Oid classid, Oid objid)
* The result is appended to "buffer". * The result is appended to "buffer".
*/ */
static void static void
getRelationDescription(StringInfo buffer, Oid relid) getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok)
{ {
HeapTuple relTup; HeapTuple relTup;
Form_pg_class relForm; Form_pg_class relForm;
...@@ -3784,7 +3976,11 @@ getRelationDescription(StringInfo buffer, Oid relid) ...@@ -3784,7 +3976,11 @@ getRelationDescription(StringInfo buffer, Oid relid)
relTup = SearchSysCache1(RELOID, relTup = SearchSysCache1(RELOID,
ObjectIdGetDatum(relid)); ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(relTup)) if (!HeapTupleIsValid(relTup))
elog(ERROR, "cache lookup failed for relation %u", relid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for relation %u", relid);
return;
}
relForm = (Form_pg_class) GETSTRUCT(relTup); relForm = (Form_pg_class) GETSTRUCT(relTup);
/* Qualify the name if not visible in search path */ /* Qualify the name if not visible in search path */
...@@ -3845,7 +4041,7 @@ getRelationDescription(StringInfo buffer, Oid relid) ...@@ -3845,7 +4041,7 @@ getRelationDescription(StringInfo buffer, Oid relid)
* subroutine for getObjectDescription: describe an operator family * subroutine for getObjectDescription: describe an operator family
*/ */
static void static void
getOpFamilyDescription(StringInfo buffer, Oid opfid) getOpFamilyDescription(StringInfo buffer, Oid opfid, bool missing_ok)
{ {
HeapTuple opfTup; HeapTuple opfTup;
Form_pg_opfamily opfForm; Form_pg_opfamily opfForm;
...@@ -3855,7 +4051,11 @@ getOpFamilyDescription(StringInfo buffer, Oid opfid) ...@@ -3855,7 +4051,11 @@ getOpFamilyDescription(StringInfo buffer, Oid opfid)
opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid)); opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
if (!HeapTupleIsValid(opfTup)) if (!HeapTupleIsValid(opfTup))
elog(ERROR, "cache lookup failed for opfamily %u", opfid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
return;
}
opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup); opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod)); amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
...@@ -3899,7 +4099,11 @@ pg_describe_object(PG_FUNCTION_ARGS) ...@@ -3899,7 +4099,11 @@ pg_describe_object(PG_FUNCTION_ARGS)
address.objectId = objid; address.objectId = objid;
address.objectSubId = objsubid; address.objectSubId = objsubid;
description = getObjectDescription(&address); description = getObjectDescription(&address, true);
if (description == NULL)
PG_RETURN_NULL();
PG_RETURN_TEXT_P(cstring_to_text(description)); PG_RETURN_TEXT_P(cstring_to_text(description));
} }
...@@ -3914,6 +4118,7 @@ pg_identify_object(PG_FUNCTION_ARGS) ...@@ -3914,6 +4118,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
int32 objsubid = PG_GETARG_INT32(2); int32 objsubid = PG_GETARG_INT32(2);
Oid schema_oid = InvalidOid; Oid schema_oid = InvalidOid;
const char *objname = NULL; const char *objname = NULL;
char *objidentity;
ObjectAddress address; ObjectAddress address;
Datum values[4]; Datum values[4];
bool nulls[4]; bool nulls[4];
...@@ -3988,12 +4193,18 @@ pg_identify_object(PG_FUNCTION_ARGS) ...@@ -3988,12 +4193,18 @@ pg_identify_object(PG_FUNCTION_ARGS)
table_close(catalog, AccessShareLock); table_close(catalog, AccessShareLock);
} }
/* object type */ /* object type, which can never be NULL */
values[0] = CStringGetTextDatum(getObjectTypeDescription(&address)); values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
nulls[0] = false; nulls[0] = false;
/*
* Before doing anything, extract the object identity. If the identity
* could not be found, set all the fields except the object type to NULL.
*/
objidentity = getObjectIdentity(&address, true);
/* schema name */ /* schema name */
if (OidIsValid(schema_oid)) if (OidIsValid(schema_oid) && objidentity)
{ {
const char *schema = quote_identifier(get_namespace_name(schema_oid)); const char *schema = quote_identifier(get_namespace_name(schema_oid));
...@@ -4004,7 +4215,7 @@ pg_identify_object(PG_FUNCTION_ARGS) ...@@ -4004,7 +4215,7 @@ pg_identify_object(PG_FUNCTION_ARGS)
nulls[1] = true; nulls[1] = true;
/* object name */ /* object name */
if (objname) if (objname && objidentity)
{ {
values[2] = CStringGetTextDatum(objname); values[2] = CStringGetTextDatum(objname);
nulls[2] = false; nulls[2] = false;
...@@ -4013,8 +4224,13 @@ pg_identify_object(PG_FUNCTION_ARGS) ...@@ -4013,8 +4224,13 @@ pg_identify_object(PG_FUNCTION_ARGS)
nulls[2] = true; nulls[2] = true;
/* object identity */ /* object identity */
values[3] = CStringGetTextDatum(getObjectIdentity(&address)); if (objidentity)
nulls[3] = false; {
values[3] = CStringGetTextDatum(objidentity);
nulls[3] = false;
}
else
nulls[3] = true;
htup = heap_form_tuple(tupdesc, values, nulls); htup = heap_form_tuple(tupdesc, values, nulls);
...@@ -4058,26 +4274,34 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS) ...@@ -4058,26 +4274,34 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
tupdesc = BlessTupleDesc(tupdesc); tupdesc = BlessTupleDesc(tupdesc);
/* object type */ /* object type */
values[0] = CStringGetTextDatum(getObjectTypeDescription(&address)); values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
nulls[0] = false; nulls[0] = false;
/* object identity */ /* object identity */
identity = getObjectIdentityParts(&address, &names, &args); identity = getObjectIdentityParts(&address, &names, &args, true);
pfree(identity); if (identity == NULL)
{
/* object_names */ nulls[1] = true;
if (names != NIL) nulls[2] = true;
values[1] = PointerGetDatum(strlist_to_textarray(names)); }
else else
values[1] = PointerGetDatum(construct_empty_array(TEXTOID)); {
nulls[1] = false; pfree(identity);
/* object_args */ /* object_names */
if (args) if (names != NIL)
values[2] = PointerGetDatum(strlist_to_textarray(args)); values[1] = PointerGetDatum(strlist_to_textarray(names));
else else
values[2] = PointerGetDatum(construct_empty_array(TEXTOID)); values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
nulls[2] = false; nulls[1] = false;
/* object_args */
if (args)
values[2] = PointerGetDatum(strlist_to_textarray(args));
else
values[2] = PointerGetDatum(construct_empty_array(TEXTOID));
nulls[2] = false;
}
htup = heap_form_tuple(tupdesc, values, nulls); htup = heap_form_tuple(tupdesc, values, nulls);
...@@ -4091,7 +4315,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS) ...@@ -4091,7 +4315,7 @@ pg_identify_object_as_address(PG_FUNCTION_ARGS)
* Keep ObjectTypeMap in sync with this. * Keep ObjectTypeMap in sync with this.
*/ */
char * char *
getObjectTypeDescription(const ObjectAddress *object) getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
{ {
StringInfoData buffer; StringInfoData buffer;
...@@ -4101,11 +4325,13 @@ getObjectTypeDescription(const ObjectAddress *object) ...@@ -4101,11 +4325,13 @@ getObjectTypeDescription(const ObjectAddress *object)
{ {
case OCLASS_CLASS: case OCLASS_CLASS:
getRelationTypeDescription(&buffer, object->objectId, getRelationTypeDescription(&buffer, object->objectId,
object->objectSubId); object->objectSubId,
missing_ok);
break; break;
case OCLASS_PROC: case OCLASS_PROC:
getProcedureTypeDescription(&buffer, object->objectId); getProcedureTypeDescription(&buffer, object->objectId,
missing_ok);
break; break;
case OCLASS_TYPE: case OCLASS_TYPE:
...@@ -4121,7 +4347,8 @@ getObjectTypeDescription(const ObjectAddress *object) ...@@ -4121,7 +4347,8 @@ getObjectTypeDescription(const ObjectAddress *object)
break; break;
case OCLASS_CONSTRAINT: case OCLASS_CONSTRAINT:
getConstraintTypeDescription(&buffer, object->objectId); getConstraintTypeDescription(&buffer, object->objectId,
missing_ok);
break; break;
case OCLASS_CONVERSION: case OCLASS_CONVERSION:
...@@ -4258,6 +4485,10 @@ getObjectTypeDescription(const ObjectAddress *object) ...@@ -4258,6 +4485,10 @@ getObjectTypeDescription(const ObjectAddress *object)
*/ */
} }
/* an empty string is equivalent to no object found */
if (buffer.len == 0)
return NULL;
return buffer.data; return buffer.data;
} }
...@@ -4265,7 +4496,8 @@ getObjectTypeDescription(const ObjectAddress *object) ...@@ -4265,7 +4496,8 @@ getObjectTypeDescription(const ObjectAddress *object)
* subroutine for getObjectTypeDescription: describe a relation type * subroutine for getObjectTypeDescription: describe a relation type
*/ */
static void static void
getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId) getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId,
bool missing_ok)
{ {
HeapTuple relTup; HeapTuple relTup;
Form_pg_class relForm; Form_pg_class relForm;
...@@ -4273,7 +4505,14 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId) ...@@ -4273,7 +4505,14 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
relTup = SearchSysCache1(RELOID, relTup = SearchSysCache1(RELOID,
ObjectIdGetDatum(relid)); ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(relTup)) if (!HeapTupleIsValid(relTup))
elog(ERROR, "cache lookup failed for relation %u", relid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for relation %u", relid);
/* fallback to "relation" for an undefined object */
appendStringInfoString(buffer, "relation");
return;
}
relForm = (Form_pg_class) GETSTRUCT(relTup); relForm = (Form_pg_class) GETSTRUCT(relTup);
switch (relForm->relkind) switch (relForm->relkind)
...@@ -4320,7 +4559,7 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId) ...@@ -4320,7 +4559,7 @@ getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
* subroutine for getObjectTypeDescription: describe a constraint type * subroutine for getObjectTypeDescription: describe a constraint type
*/ */
static void static void
getConstraintTypeDescription(StringInfo buffer, Oid constroid) getConstraintTypeDescription(StringInfo buffer, Oid constroid, bool missing_ok)
{ {
Relation constrRel; Relation constrRel;
HeapTuple constrTup; HeapTuple constrTup;
...@@ -4330,7 +4569,16 @@ getConstraintTypeDescription(StringInfo buffer, Oid constroid) ...@@ -4330,7 +4569,16 @@ getConstraintTypeDescription(StringInfo buffer, Oid constroid)
constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid, constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid,
constroid); constroid);
if (!HeapTupleIsValid(constrTup)) if (!HeapTupleIsValid(constrTup))
elog(ERROR, "cache lookup failed for constraint %u", constroid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for constraint %u", constroid);
table_close(constrRel, AccessShareLock);
/* fallback to "constraint" for an undefined object */
appendStringInfoString(buffer, "constraint");
return;
}
constrForm = (Form_pg_constraint) GETSTRUCT(constrTup); constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
...@@ -4348,7 +4596,8 @@ getConstraintTypeDescription(StringInfo buffer, Oid constroid) ...@@ -4348,7 +4596,8 @@ getConstraintTypeDescription(StringInfo buffer, Oid constroid)
* subroutine for getObjectTypeDescription: describe a procedure type * subroutine for getObjectTypeDescription: describe a procedure type
*/ */
static void static void
getProcedureTypeDescription(StringInfo buffer, Oid procid) getProcedureTypeDescription(StringInfo buffer, Oid procid,
bool missing_ok)
{ {
HeapTuple procTup; HeapTuple procTup;
Form_pg_proc procForm; Form_pg_proc procForm;
...@@ -4356,7 +4605,14 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid) ...@@ -4356,7 +4605,14 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid)
procTup = SearchSysCache1(PROCOID, procTup = SearchSysCache1(PROCOID,
ObjectIdGetDatum(procid)); ObjectIdGetDatum(procid));
if (!HeapTupleIsValid(procTup)) if (!HeapTupleIsValid(procTup))
elog(ERROR, "cache lookup failed for procedure %u", procid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for procedure %u", procid);
/* fallback to "procedure" for an undefined object */
appendStringInfoString(buffer, "routine");
return;
}
procForm = (Form_pg_proc) GETSTRUCT(procTup); procForm = (Form_pg_proc) GETSTRUCT(procTup);
if (procForm->prokind == PROKIND_AGGREGATE) if (procForm->prokind == PROKIND_AGGREGATE)
...@@ -4373,12 +4629,13 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid) ...@@ -4373,12 +4629,13 @@ getProcedureTypeDescription(StringInfo buffer, Oid procid)
* Obtain a given object's identity, as a palloc'ed string. * Obtain a given object's identity, as a palloc'ed string.
* *
* This is for machine consumption, so it's not translated. All elements are * This is for machine consumption, so it's not translated. All elements are
* schema-qualified when appropriate. * schema-qualified when appropriate. Returns NULL if the object could not
* be found.
*/ */
char * char *
getObjectIdentity(const ObjectAddress *object) getObjectIdentity(const ObjectAddress *object, bool missing_ok)
{ {
return getObjectIdentityParts(object, NULL, NULL); return getObjectIdentityParts(object, NULL, NULL, missing_ok);
} }
/* /*
...@@ -4387,11 +4644,13 @@ getObjectIdentity(const ObjectAddress *object) ...@@ -4387,11 +4644,13 @@ getObjectIdentity(const ObjectAddress *object)
* There are two sets of return values: the identity itself as a palloc'd * There are two sets of return values: the identity itself as a palloc'd
* string is returned. objname and objargs, if not NULL, are output parameters * string is returned. objname and objargs, if not NULL, are output parameters
* that receive lists of C-strings that are useful to give back to * that receive lists of C-strings that are useful to give back to
* get_object_address() to reconstruct the ObjectAddress. * get_object_address() to reconstruct the ObjectAddress. Returns NULL if
* the object could not be found.
*/ */
char * char *
getObjectIdentityParts(const ObjectAddress *object, getObjectIdentityParts(const ObjectAddress *object,
List **objname, List **objargs) List **objname, List **objargs,
bool missing_ok)
{ {
StringInfoData buffer; StringInfoData buffer;
...@@ -4413,31 +4672,63 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4413,31 +4672,63 @@ getObjectIdentityParts(const ObjectAddress *object,
switch (getObjectClass(object)) switch (getObjectClass(object))
{ {
case OCLASS_CLASS: case OCLASS_CLASS:
getRelationIdentity(&buffer, object->objectId, objname);
if (object->objectSubId != 0)
{ {
char *attr; char *attr = NULL;
attr = get_attname(object->objectId, object->objectSubId, /*
false); * Check for the attribute first, so as if it is missing we
appendStringInfo(&buffer, ".%s", quote_identifier(attr)); * can skip the entire relation description.
if (objname) */
*objname = lappend(*objname, attr); if (object->objectSubId != 0)
{
attr = get_attname(object->objectId,
object->objectSubId,
missing_ok);
if (missing_ok && attr == NULL)
break;
}
getRelationIdentity(&buffer, object->objectId, objname,
missing_ok);
if (objname && *objname == NIL)
break;
if (attr)
{
appendStringInfo(&buffer, ".%s",
quote_identifier(attr));
if (objname)
*objname = lappend(*objname, attr);
}
} }
break; break;
case OCLASS_PROC: case OCLASS_PROC:
appendStringInfoString(&buffer, {
format_procedure_qualified(object->objectId)); bits16 flags = FORMAT_PROC_FORCE_QUALIFY | FORMAT_PROC_INVALID_AS_NULL;
if (objname) char *proname = format_procedure_extended(object->objectId,
format_procedure_parts(object->objectId, objname, objargs); flags);
break; if (proname == NULL)
break;
appendStringInfoString(&buffer, proname);
if (objname)
format_procedure_parts(object->objectId, objname, objargs,
missing_ok);
break;
}
case OCLASS_TYPE: case OCLASS_TYPE:
{ {
bits16 flags = FORMAT_TYPE_INVALID_AS_NULL | FORMAT_TYPE_FORCE_QUALIFY;
char *typeout; char *typeout;
typeout = format_type_be_qualified(object->objectId); typeout = format_type_extended(object->objectId, -1, flags);
if (typeout == NULL)
break;
appendStringInfoString(&buffer, typeout); appendStringInfoString(&buffer, typeout);
if (objname) if (objname)
*objname = list_make1(typeout); *objname = list_make1(typeout);
...@@ -4456,8 +4747,14 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4456,8 +4747,14 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId); object->objectId);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for cast %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for cast %u",
object->objectId);
table_close(castRel, AccessShareLock);
break;
}
castForm = (Form_pg_cast) GETSTRUCT(tup); castForm = (Form_pg_cast) GETSTRUCT(tup);
...@@ -4484,8 +4781,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4484,8 +4781,12 @@ getObjectIdentityParts(const ObjectAddress *object,
collTup = SearchSysCache1(COLLOID, collTup = SearchSysCache1(COLLOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(collTup)) if (!HeapTupleIsValid(collTup))
elog(ERROR, "cache lookup failed for collation %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for collation %u",
object->objectId);
break;
}
coll = (Form_pg_collation) GETSTRUCT(collTup); coll = (Form_pg_collation) GETSTRUCT(collTup);
schema = get_namespace_name_or_temp(coll->collnamespace); schema = get_namespace_name_or_temp(coll->collnamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4506,15 +4807,20 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4506,15 +4807,20 @@ getObjectIdentityParts(const ObjectAddress *object,
conTup = SearchSysCache1(CONSTROID, conTup = SearchSysCache1(CONSTROID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(conTup)) if (!HeapTupleIsValid(conTup))
elog(ERROR, "cache lookup failed for constraint %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for constraint %u",
object->objectId);
break;
}
con = (Form_pg_constraint) GETSTRUCT(conTup); con = (Form_pg_constraint) GETSTRUCT(conTup);
if (OidIsValid(con->conrelid)) if (OidIsValid(con->conrelid))
{ {
appendStringInfo(&buffer, "%s on ", appendStringInfo(&buffer, "%s on ",
quote_identifier(NameStr(con->conname))); quote_identifier(NameStr(con->conname)));
getRelationIdentity(&buffer, con->conrelid, objname); getRelationIdentity(&buffer, con->conrelid, objname,
false);
if (objname) if (objname)
*objname = lappend(*objname, pstrdup(NameStr(con->conname))); *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
} }
...@@ -4529,7 +4835,8 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4529,7 +4835,8 @@ getObjectIdentityParts(const ObjectAddress *object,
appendStringInfo(&buffer, "%s on %s", appendStringInfo(&buffer, "%s on %s",
quote_identifier(NameStr(con->conname)), quote_identifier(NameStr(con->conname)),
getObjectIdentityParts(&domain, objname, objargs)); getObjectIdentityParts(&domain, objname,
objargs, false));
if (objname) if (objname)
*objargs = lappend(*objargs, pstrdup(NameStr(con->conname))); *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
...@@ -4548,8 +4855,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4548,8 +4855,12 @@ getObjectIdentityParts(const ObjectAddress *object,
conTup = SearchSysCache1(CONVOID, conTup = SearchSysCache1(CONVOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(conTup)) if (!HeapTupleIsValid(conTup))
elog(ERROR, "cache lookup failed for conversion %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for conversion %u",
object->objectId);
break;
}
conForm = (Form_pg_conversion) GETSTRUCT(conTup); conForm = (Form_pg_conversion) GETSTRUCT(conTup);
schema = get_namespace_name_or_temp(conForm->connamespace); schema = get_namespace_name_or_temp(conForm->connamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4585,8 +4896,15 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4585,8 +4896,15 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = systable_getnext(adscan); tup = systable_getnext(adscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for attrdef %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for attrdef %u",
object->objectId);
systable_endscan(adscan);
table_close(attrdefDesc, AccessShareLock);
break;
}
attrdef = (Form_pg_attrdef) GETSTRUCT(tup); attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
...@@ -4596,7 +4914,8 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4596,7 +4914,8 @@ getObjectIdentityParts(const ObjectAddress *object,
appendStringInfo(&buffer, "for %s", appendStringInfo(&buffer, "for %s",
getObjectIdentityParts(&colobject, getObjectIdentityParts(&colobject,
objname, objargs)); objname, objargs,
false));
systable_endscan(adscan); systable_endscan(adscan);
table_close(attrdefDesc, AccessShareLock); table_close(attrdefDesc, AccessShareLock);
...@@ -4611,8 +4930,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4611,8 +4930,12 @@ getObjectIdentityParts(const ObjectAddress *object,
langTup = SearchSysCache1(LANGOID, langTup = SearchSysCache1(LANGOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(langTup)) if (!HeapTupleIsValid(langTup))
elog(ERROR, "cache lookup failed for language %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for language %u",
object->objectId);
break;
}
langForm = (Form_pg_language) GETSTRUCT(langTup); langForm = (Form_pg_language) GETSTRUCT(langTup);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
quote_identifier(NameStr(langForm->lanname))); quote_identifier(NameStr(langForm->lanname)));
...@@ -4622,6 +4945,8 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4622,6 +4945,8 @@ getObjectIdentityParts(const ObjectAddress *object,
break; break;
} }
case OCLASS_LARGEOBJECT: case OCLASS_LARGEOBJECT:
if (!LargeObjectExists(object->objectId))
break;
appendStringInfo(&buffer, "%u", appendStringInfo(&buffer, "%u",
object->objectId); object->objectId);
if (objname) if (objname)
...@@ -4629,11 +4954,18 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4629,11 +4954,18 @@ getObjectIdentityParts(const ObjectAddress *object,
break; break;
case OCLASS_OPERATOR: case OCLASS_OPERATOR:
appendStringInfoString(&buffer, {
format_operator_qualified(object->objectId)); bits16 flags = FORMAT_OPERATOR_FORCE_QUALIFY | FORMAT_OPERATOR_INVALID_AS_NULL;
if (objname) char *oprname = format_operator_extended(object->objectId,
format_operator_parts(object->objectId, objname, objargs); flags);
break; if (oprname == NULL)
break;
appendStringInfoString(&buffer, oprname);
if (objname)
format_operator_parts(object->objectId, objname, objargs, missing_ok);
break;
}
case OCLASS_OPCLASS: case OCLASS_OPCLASS:
{ {
...@@ -4646,8 +4978,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4646,8 +4978,12 @@ getObjectIdentityParts(const ObjectAddress *object,
opcTup = SearchSysCache1(CLAOID, opcTup = SearchSysCache1(CLAOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(opcTup)) if (!HeapTupleIsValid(opcTup))
elog(ERROR, "cache lookup failed for opclass %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for opclass %u",
object->objectId);
break;
}
opcForm = (Form_pg_opclass) GETSTRUCT(opcTup); opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
schema = get_namespace_name_or_temp(opcForm->opcnamespace); schema = get_namespace_name_or_temp(opcForm->opcnamespace);
...@@ -4673,7 +5009,8 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4673,7 +5009,8 @@ getObjectIdentityParts(const ObjectAddress *object,
} }
case OCLASS_OPFAMILY: case OCLASS_OPFAMILY:
getOpFamilyIdentity(&buffer, object->objectId, objname); getOpFamilyIdentity(&buffer, object->objectId, objname,
missing_ok);
break; break;
case OCLASS_AM: case OCLASS_AM:
...@@ -4682,8 +5019,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4682,8 +5019,12 @@ getObjectIdentityParts(const ObjectAddress *object,
amname = get_am_name(object->objectId); amname = get_am_name(object->objectId);
if (!amname) if (!amname)
elog(ERROR, "cache lookup failed for access method %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for access method %u",
object->objectId);
break;
}
appendStringInfoString(&buffer, quote_identifier(amname)); appendStringInfoString(&buffer, quote_identifier(amname));
if (objname) if (objname)
*objname = list_make1(amname); *objname = list_make1(amname);
...@@ -4715,13 +5056,21 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4715,13 +5056,21 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = systable_getnext(amscan); tup = systable_getnext(amscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amop entry %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for amop entry %u",
object->objectId);
systable_endscan(amscan);
table_close(amopDesc, AccessShareLock);
break;
}
amopForm = (Form_pg_amop) GETSTRUCT(tup); amopForm = (Form_pg_amop) GETSTRUCT(tup);
initStringInfo(&opfam); initStringInfo(&opfam);
getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname); getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname,
false);
ltype = format_type_be_qualified(amopForm->amoplefttype); ltype = format_type_be_qualified(amopForm->amoplefttype);
rtype = format_type_be_qualified(amopForm->amoprighttype); rtype = format_type_be_qualified(amopForm->amoprighttype);
...@@ -4769,13 +5118,21 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4769,13 +5118,21 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = systable_getnext(amscan); tup = systable_getnext(amscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for amproc entry %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for amproc entry %u",
object->objectId);
systable_endscan(amscan);
table_close(amprocDesc, AccessShareLock);
break;
}
amprocForm = (Form_pg_amproc) GETSTRUCT(tup); amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
initStringInfo(&opfam); initStringInfo(&opfam);
getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname); getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname,
false);
ltype = format_type_be_qualified(amprocForm->amproclefttype); ltype = format_type_be_qualified(amprocForm->amproclefttype);
rtype = format_type_be_qualified(amprocForm->amprocrighttype); rtype = format_type_be_qualified(amprocForm->amprocrighttype);
...@@ -4810,14 +5167,20 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4810,14 +5167,20 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId); object->objectId);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for rule %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for rule %u",
object->objectId);
table_close(ruleDesc, AccessShareLock);
break;
}
rule = (Form_pg_rewrite) GETSTRUCT(tup); rule = (Form_pg_rewrite) GETSTRUCT(tup);
appendStringInfo(&buffer, "%s on ", appendStringInfo(&buffer, "%s on ",
quote_identifier(NameStr(rule->rulename))); quote_identifier(NameStr(rule->rulename)));
getRelationIdentity(&buffer, rule->ev_class, objname); getRelationIdentity(&buffer, rule->ev_class, objname, false);
if (objname) if (objname)
*objname = lappend(*objname, pstrdup(NameStr(rule->rulename))); *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
...@@ -4837,14 +5200,20 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4837,14 +5200,20 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId); object->objectId);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for trigger %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for trigger %u",
object->objectId);
table_close(trigDesc, AccessShareLock);
break;
}
trig = (Form_pg_trigger) GETSTRUCT(tup); trig = (Form_pg_trigger) GETSTRUCT(tup);
appendStringInfo(&buffer, "%s on ", appendStringInfo(&buffer, "%s on ",
quote_identifier(NameStr(trig->tgname))); quote_identifier(NameStr(trig->tgname)));
getRelationIdentity(&buffer, trig->tgrelid, objname); getRelationIdentity(&buffer, trig->tgrelid, objname, false);
if (objname) if (objname)
*objname = lappend(*objname, pstrdup(NameStr(trig->tgname))); *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
...@@ -4858,8 +5227,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4858,8 +5227,12 @@ getObjectIdentityParts(const ObjectAddress *object,
nspname = get_namespace_name_or_temp(object->objectId); nspname = get_namespace_name_or_temp(object->objectId);
if (!nspname) if (!nspname)
elog(ERROR, "cache lookup failed for namespace %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for namespace %u",
object->objectId);
break;
}
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
quote_identifier(nspname)); quote_identifier(nspname));
if (objname) if (objname)
...@@ -4876,8 +5249,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4876,8 +5249,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(STATEXTOID, tup = SearchSysCache1(STATEXTOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for statistics object %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for statistics object %u",
object->objectId);
break;
}
formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup); formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
schema = get_namespace_name_or_temp(formStatistic->stxnamespace); schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4899,8 +5276,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4899,8 +5276,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(TSPARSEROID, tup = SearchSysCache1(TSPARSEROID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search parser %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search parser %u",
object->objectId);
break;
}
formParser = (Form_pg_ts_parser) GETSTRUCT(tup); formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
schema = get_namespace_name_or_temp(formParser->prsnamespace); schema = get_namespace_name_or_temp(formParser->prsnamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4922,8 +5303,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4922,8 +5303,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(TSDICTOID, tup = SearchSysCache1(TSDICTOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search dictionary %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search dictionary %u",
object->objectId);
break;
}
formDict = (Form_pg_ts_dict) GETSTRUCT(tup); formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
schema = get_namespace_name_or_temp(formDict->dictnamespace); schema = get_namespace_name_or_temp(formDict->dictnamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4945,8 +5330,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4945,8 +5330,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(TSTEMPLATEOID, tup = SearchSysCache1(TSTEMPLATEOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search template %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search template %u",
object->objectId);
break;
}
formTmpl = (Form_pg_ts_template) GETSTRUCT(tup); formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
schema = get_namespace_name_or_temp(formTmpl->tmplnamespace); schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4968,8 +5357,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4968,8 +5357,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(TSCONFIGOID, tup = SearchSysCache1(TSCONFIGOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for text search configuration %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for text search configuration %u",
object->objectId);
break;
}
formCfg = (Form_pg_ts_config) GETSTRUCT(tup); formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
schema = get_namespace_name_or_temp(formCfg->cfgnamespace); schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -4986,7 +5379,9 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -4986,7 +5379,9 @@ getObjectIdentityParts(const ObjectAddress *object,
{ {
char *username; char *username;
username = GetUserNameFromId(object->objectId, false); username = GetUserNameFromId(object->objectId, missing_ok);
if (!username)
break;
if (objname) if (objname)
*objname = list_make1(username); *objname = list_make1(username);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -5000,8 +5395,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5000,8 +5395,12 @@ getObjectIdentityParts(const ObjectAddress *object,
datname = get_database_name(object->objectId); datname = get_database_name(object->objectId);
if (!datname) if (!datname)
elog(ERROR, "cache lookup failed for database %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for database %u",
object->objectId);
break;
}
if (objname) if (objname)
*objname = list_make1(datname); *objname = list_make1(datname);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -5015,8 +5414,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5015,8 +5414,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tblspace = get_tablespace_name(object->objectId); tblspace = get_tablespace_name(object->objectId);
if (!tblspace) if (!tblspace)
elog(ERROR, "cache lookup failed for tablespace %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for tablespace %u",
object->objectId);
break;
}
if (objname) if (objname)
*objname = list_make1(tblspace); *objname = list_make1(tblspace);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
...@@ -5028,10 +5431,14 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5028,10 +5431,14 @@ getObjectIdentityParts(const ObjectAddress *object,
{ {
ForeignDataWrapper *fdw; ForeignDataWrapper *fdw;
fdw = GetForeignDataWrapper(object->objectId); fdw = GetForeignDataWrapperExtended(object->objectId,
appendStringInfoString(&buffer, quote_identifier(fdw->fdwname)); missing_ok);
if (objname) if (fdw)
*objname = list_make1(pstrdup(fdw->fdwname)); {
appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
if (objname)
*objname = list_make1(pstrdup(fdw->fdwname));
}
break; break;
} }
...@@ -5039,11 +5446,15 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5039,11 +5446,15 @@ getObjectIdentityParts(const ObjectAddress *object,
{ {
ForeignServer *srv; ForeignServer *srv;
srv = GetForeignServer(object->objectId); srv = GetForeignServerExtended(object->objectId,
appendStringInfoString(&buffer, missing_ok);
quote_identifier(srv->servername)); if (srv)
if (objname) {
*objname = list_make1(pstrdup(srv->servername)); appendStringInfoString(&buffer,
quote_identifier(srv->servername));
if (objname)
*objname = list_make1(pstrdup(srv->servername));
}
break; break;
} }
...@@ -5058,8 +5469,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5058,8 +5469,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(USERMAPPINGOID, tup = SearchSysCache1(USERMAPPINGOID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for user mapping %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for user mapping %u",
object->objectId);
break;
}
umform = (Form_pg_user_mapping) GETSTRUCT(tup); umform = (Form_pg_user_mapping) GETSTRUCT(tup);
useid = umform->umuser; useid = umform->umuser;
srv = GetForeignServer(umform->umserver); srv = GetForeignServer(umform->umserver);
...@@ -5106,8 +5521,16 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5106,8 +5521,16 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = systable_getnext(rcscan); tup = systable_getnext(rcscan);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for default ACL %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for default ACL %u",
object->objectId);
systable_endscan(rcscan);
table_close(defaclrel, AccessShareLock);
break;
}
defacl = (Form_pg_default_acl) GETSTRUCT(tup); defacl = (Form_pg_default_acl) GETSTRUCT(tup);
...@@ -5169,8 +5592,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5169,8 +5592,12 @@ getObjectIdentityParts(const ObjectAddress *object,
extname = get_extension_name(object->objectId); extname = get_extension_name(object->objectId);
if (!extname) if (!extname)
elog(ERROR, "cache lookup failed for extension %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for extension %u",
object->objectId);
break;
}
appendStringInfoString(&buffer, quote_identifier(extname)); appendStringInfoString(&buffer, quote_identifier(extname));
if (objname) if (objname)
*objname = list_make1(extname); *objname = list_make1(extname);
...@@ -5189,8 +5616,12 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5189,8 +5616,12 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(EVENTTRIGGEROID, tup = SearchSysCache1(EVENTTRIGGEROID,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for event trigger %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for event trigger %u",
object->objectId);
break;
}
trigForm = (Form_pg_event_trigger) GETSTRUCT(tup); trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
appendStringInfoString(&buffer, appendStringInfoString(&buffer,
quote_identifier(NameStr(trigForm->evtname))); quote_identifier(NameStr(trigForm->evtname)));
...@@ -5210,14 +5641,20 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5210,14 +5641,20 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId); object->objectId);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for policy %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for policy %u",
object->objectId);
table_close(polDesc, AccessShareLock);
break;
}
policy = (Form_pg_policy) GETSTRUCT(tup); policy = (Form_pg_policy) GETSTRUCT(tup);
appendStringInfo(&buffer, "%s on ", appendStringInfo(&buffer, "%s on ",
quote_identifier(NameStr(policy->polname))); quote_identifier(NameStr(policy->polname)));
getRelationIdentity(&buffer, policy->polrelid, objname); getRelationIdentity(&buffer, policy->polrelid, objname, false);
if (objname) if (objname)
*objname = lappend(*objname, pstrdup(NameStr(policy->polname))); *objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
...@@ -5229,11 +5666,14 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5229,11 +5666,14 @@ getObjectIdentityParts(const ObjectAddress *object,
{ {
char *pubname; char *pubname;
pubname = get_publication_name(object->objectId, false); pubname = get_publication_name(object->objectId, missing_ok);
appendStringInfoString(&buffer, if (pubname)
quote_identifier(pubname)); {
if (objname) appendStringInfoString(&buffer,
*objname = list_make1(pubname); quote_identifier(pubname));
if (objname)
*objname = list_make1(pubname);
}
break; break;
} }
...@@ -5246,13 +5686,17 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5246,13 +5686,17 @@ getObjectIdentityParts(const ObjectAddress *object,
tup = SearchSysCache1(PUBLICATIONREL, tup = SearchSysCache1(PUBLICATIONREL,
ObjectIdGetDatum(object->objectId)); ObjectIdGetDatum(object->objectId));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for publication table %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "cache lookup failed for publication table %u",
object->objectId);
break;
}
prform = (Form_pg_publication_rel) GETSTRUCT(tup); prform = (Form_pg_publication_rel) GETSTRUCT(tup);
pubname = get_publication_name(prform->prpubid, false); pubname = get_publication_name(prform->prpubid, false);
getRelationIdentity(&buffer, prform->prrelid, objname); getRelationIdentity(&buffer, prform->prrelid, objname, false);
appendStringInfo(&buffer, " in publication %s", pubname); appendStringInfo(&buffer, " in publication %s", pubname);
if (objargs) if (objargs)
...@@ -5266,11 +5710,14 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5266,11 +5710,14 @@ getObjectIdentityParts(const ObjectAddress *object,
{ {
char *subname; char *subname;
subname = get_subscription_name(object->objectId, false); subname = get_subscription_name(object->objectId, missing_ok);
appendStringInfoString(&buffer, if (subname)
quote_identifier(subname)); {
if (objname) appendStringInfoString(&buffer,
*objname = list_make1(subname); quote_identifier(subname));
if (objname)
*objname = list_make1(subname);
}
break; break;
} }
...@@ -5289,8 +5736,14 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5289,8 +5736,14 @@ getObjectIdentityParts(const ObjectAddress *object,
object->objectId); object->objectId);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "could not find tuple for transform %u", {
object->objectId); if (!missing_ok)
elog(ERROR, "could not find tuple for transform %u",
object->objectId);
table_close(transformDesc, AccessShareLock);
break;
}
transform = (Form_pg_transform) GETSTRUCT(tup); transform = (Form_pg_transform) GETSTRUCT(tup);
...@@ -5316,20 +5769,34 @@ getObjectIdentityParts(const ObjectAddress *object, ...@@ -5316,20 +5769,34 @@ getObjectIdentityParts(const ObjectAddress *object,
*/ */
} }
/* if (!missing_ok)
* If a get_object_address representation was requested, make sure we are {
* providing one. We don't check objargs, because many of the cases above /*
* leave it as NIL. * If a get_object_address() representation was requested, make sure
*/ * we are providing one. We don't check objargs, because many of the
if (objname && *objname == NIL) * cases above leave it as NIL.
elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"", */
(int) getObjectClass(object), buffer.data); if (objname && *objname == NIL)
elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"",
(int) getObjectClass(object), buffer.data);
}
else
{
/* an empty buffer is equivalent to no object found */
if (buffer.len == 0)
{
Assert((objname == NULL || *objname == NIL) &&
(objargs == NULL || *objargs == NIL));
return NULL;
}
}
return buffer.data; return buffer.data;
} }
static void static void
getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object) getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
bool missing_ok)
{ {
HeapTuple opfTup; HeapTuple opfTup;
Form_pg_opfamily opfForm; Form_pg_opfamily opfForm;
...@@ -5339,7 +5806,11 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object) ...@@ -5339,7 +5806,11 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object)
opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid)); opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
if (!HeapTupleIsValid(opfTup)) if (!HeapTupleIsValid(opfTup))
elog(ERROR, "cache lookup failed for opfamily %u", opfid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
return;
}
opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup); opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod)); amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
...@@ -5368,7 +5839,8 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object) ...@@ -5368,7 +5839,8 @@ getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object)
* StringInfo. * StringInfo.
*/ */
static void static void
getRelationIdentity(StringInfo buffer, Oid relid, List **object) getRelationIdentity(StringInfo buffer, Oid relid, List **object,
bool missing_ok)
{ {
HeapTuple relTup; HeapTuple relTup;
Form_pg_class relForm; Form_pg_class relForm;
...@@ -5377,7 +5849,14 @@ getRelationIdentity(StringInfo buffer, Oid relid, List **object) ...@@ -5377,7 +5849,14 @@ getRelationIdentity(StringInfo buffer, Oid relid, List **object)
relTup = SearchSysCache1(RELOID, relTup = SearchSysCache1(RELOID,
ObjectIdGetDatum(relid)); ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(relTup)) if (!HeapTupleIsValid(relTup))
elog(ERROR, "cache lookup failed for relation %u", relid); {
if (!missing_ok)
elog(ERROR, "cache lookup failed for relation %u", relid);
if (object)
*object = NIL;
return;
}
relForm = (Form_pg_class) GETSTRUCT(relTup); relForm = (Form_pg_class) GETSTRUCT(relTup);
schema = get_namespace_name_or_temp(relForm->relnamespace); schema = get_namespace_name_or_temp(relForm->relnamespace);
......
...@@ -160,7 +160,7 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object, ...@@ -160,7 +160,7 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"", errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(object), getObjectDescription(object, false),
get_extension_name(oldext)))); get_extension_name(oldext))));
} }
} }
...@@ -536,7 +536,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId, ...@@ -536,7 +536,7 @@ changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot remove dependency on %s because it is a system object", 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 * We can handle adding a dependency on something pinned, though, since
......
...@@ -638,7 +638,7 @@ checkSharedDependencies(Oid classId, Oid objectId, ...@@ -638,7 +638,7 @@ checkSharedDependencies(Oid classId, Oid objectId,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because it is required by the database system", errmsg("cannot drop %s because it is required by the database system",
getObjectDescription(&object)))); getObjectDescription(&object, false))));
} }
object.classId = sdepForm->classid; object.classId = sdepForm->classid;
...@@ -1147,7 +1147,7 @@ storeObjectDescription(StringInfo descs, ...@@ -1147,7 +1147,7 @@ storeObjectDescription(StringInfo descs,
SharedDependencyType deptype, SharedDependencyType deptype,
int count) int count)
{ {
char *objdesc = getObjectDescription(object); char *objdesc = getObjectDescription(object, false);
/* separate entries with a newline */ /* separate entries with a newline */
if (descs->len != 0) if (descs->len != 0)
...@@ -1283,7 +1283,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior) ...@@ -1283,7 +1283,7 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop objects owned by %s because they are " errmsg("cannot drop objects owned by %s because they are "
"required by the database system", "required by the database system",
getObjectDescription(&obj)))); getObjectDescription(&obj, false))));
} }
ScanKeyInit(&key[0], ScanKeyInit(&key[0],
...@@ -1429,7 +1429,7 @@ shdepReassignOwned(List *roleids, Oid newrole) ...@@ -1429,7 +1429,7 @@ shdepReassignOwned(List *roleids, Oid newrole)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot reassign ownership of objects owned by %s because they are required by the database system", 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 * 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 ...@@ -1267,10 +1267,11 @@ EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool no
/* object identity, objname and objargs */ /* object identity, objname and objargs */
obj->objidentity = obj->objidentity =
getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs); getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs,
false);
/* object type */ /* object type */
obj->objecttype = getObjectTypeDescription(&obj->address); obj->objecttype = getObjectTypeDescription(&obj->address, false);
slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next); slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
...@@ -1929,8 +1930,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS) ...@@ -1929,8 +1930,8 @@ pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
else if (cmd->type == SCT_AlterTSConfig) else if (cmd->type == SCT_AlterTSConfig)
addr = cmd->d.atscfg.address; addr = cmd->d.atscfg.address;
type = getObjectTypeDescription(&addr); type = getObjectTypeDescription(&addr, false);
identity = getObjectIdentity(&addr); identity = getObjectIdentity(&addr, false);
/* /*
* Obtain schema name, if any ("pg_temp" if a temp * Obtain schema name, if any ("pg_temp" if a temp
......
...@@ -2919,7 +2919,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o ...@@ -2919,7 +2919,7 @@ AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *o
errmsg("extension \"%s\" does not support SET SCHEMA", errmsg("extension \"%s\" does not support SET SCHEMA",
NameStr(extForm->extname)), NameStr(extForm->extname)),
errdetail("%s is not in the extension's schema \"%s\"", errdetail("%s is not in the extension's schema \"%s\"",
getObjectDescription(&dep), getObjectDescription(&dep, false),
get_namespace_name(oldNspOid)))); get_namespace_name(oldNspOid))));
} }
...@@ -3328,7 +3328,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt, ...@@ -3328,7 +3328,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"", errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(&object), getObjectDescription(&object, false),
get_extension_name(oldExtension)))); get_extension_name(oldExtension))));
/* /*
...@@ -3368,7 +3368,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt, ...@@ -3368,7 +3368,7 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is not a member of extension \"%s\"", errmsg("%s is not a member of extension \"%s\"",
getObjectDescription(&object), getObjectDescription(&object, false),
stmt->extname))); stmt->extname)));
/* /*
......
...@@ -11304,7 +11304,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -11304,7 +11304,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
{ {
/* Not expecting any other direct dependencies... */ /* Not expecting any other direct dependencies... */
elog(ERROR, "unexpected object depending on column: %s", elog(ERROR, "unexpected object depending on column: %s",
getObjectDescription(&foundObject)); getObjectDescription(&foundObject, false));
} }
break; break;
} }
...@@ -11320,7 +11320,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -11320,7 +11320,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot alter type of a column used by a view or rule"), errmsg("cannot alter type of a column used by a view or rule"),
errdetail("%s depends on column \"%s\"", errdetail("%s depends on column \"%s\"",
getObjectDescription(&foundObject), getObjectDescription(&foundObject, false),
colName))); colName)));
break; break;
...@@ -11339,7 +11339,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -11339,7 +11339,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot alter type of a column used in a trigger definition"), errmsg("cannot alter type of a column used in a trigger definition"),
errdetail("%s depends on column \"%s\"", errdetail("%s depends on column \"%s\"",
getObjectDescription(&foundObject), getObjectDescription(&foundObject, false),
colName))); colName)));
break; break;
...@@ -11357,7 +11357,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -11357,7 +11357,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot alter type of a column used in a policy definition"), errmsg("cannot alter type of a column used in a policy definition"),
errdetail("%s depends on column \"%s\"", errdetail("%s depends on column \"%s\"",
getObjectDescription(&foundObject), getObjectDescription(&foundObject, false),
colName))); colName)));
break; break;
...@@ -11418,7 +11418,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -11418,7 +11418,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
* a column. * a column.
*/ */
elog(ERROR, "unexpected object depending on column: %s", elog(ERROR, "unexpected object depending on column: %s",
getObjectDescription(&foundObject)); getObjectDescription(&foundObject, false));
break; break;
/* /*
...@@ -11474,7 +11474,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, ...@@ -11474,7 +11474,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
foundDep->refobjsubid != 0) foundDep->refobjsubid != 0)
) )
elog(ERROR, "found unexpected dependency for column: %s", elog(ERROR, "found unexpected dependency for column: %s",
getObjectDescription(&foundObject)); getObjectDescription(&foundObject, false));
CatalogTupleDelete(depRel, &depTup->t_self); CatalogTupleDelete(depRel, &depTup->t_self);
} }
......
...@@ -418,7 +418,8 @@ format_procedure_extended(Oid procedure_oid, bits16 flags) ...@@ -418,7 +418,8 @@ format_procedure_extended(Oid procedure_oid, bits16 flags)
* This can be used to feed get_object_address. * This can be used to feed get_object_address.
*/ */
void 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; HeapTuple proctup;
Form_pg_proc procform; Form_pg_proc procform;
...@@ -428,7 +429,11 @@ format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs) ...@@ -428,7 +429,11 @@ format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid)); proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
if (!HeapTupleIsValid(proctup)) 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); procform = (Form_pg_proc) GETSTRUCT(proctup);
nargs = procform->pronargs; nargs = procform->pronargs;
...@@ -856,15 +861,20 @@ format_operator_qualified(Oid operator_oid) ...@@ -856,15 +861,20 @@ format_operator_qualified(Oid operator_oid)
} }
void 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; HeapTuple opertup;
Form_pg_operator oprForm; Form_pg_operator oprForm;
opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid)); opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
if (!HeapTupleIsValid(opertup)) 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); oprForm = (Form_pg_operator) GETSTRUCT(opertup);
*objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace), *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
......
...@@ -70,14 +70,18 @@ extern bool get_object_namensp_unique(Oid class_id); ...@@ -70,14 +70,18 @@ extern bool get_object_namensp_unique(Oid class_id);
extern HeapTuple get_catalog_object_by_oid(Relation catalog, extern HeapTuple get_catalog_object_by_oid(Relation catalog,
AttrNumber oidcol, Oid objectId); 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 char *getObjectDescriptionOids(Oid classid, Oid objid);
extern int read_objtype_from_string(const char *objtype); extern int read_objtype_from_string(const char *objtype);
extern char *getObjectTypeDescription(const ObjectAddress *object); extern char *getObjectTypeDescription(const ObjectAddress *object,
extern char *getObjectIdentity(const ObjectAddress *address); bool missing_ok);
extern char *getObjectIdentity(const ObjectAddress *address,
bool missing_ok);
extern char *getObjectIdentityParts(const ObjectAddress *address, 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 struct ArrayType *strlist_to_textarray(List *list);
extern ObjectType get_relkind_objtype(char relkind); extern ObjectType get_relkind_objtype(char relkind);
......
...@@ -29,10 +29,11 @@ extern List *stringToQualifiedNameList(const char *string); ...@@ -29,10 +29,11 @@ extern List *stringToQualifiedNameList(const char *string);
extern char *format_procedure(Oid procedure_oid); extern char *format_procedure(Oid procedure_oid);
extern char *format_procedure_qualified(Oid procedure_oid); extern char *format_procedure_qualified(Oid procedure_oid);
extern void format_procedure_parts(Oid operator_oid, List **objnames, 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(Oid operator_oid);
extern char *format_operator_qualified(Oid operator_oid); extern char *format_operator_qualified(Oid operator_oid);
extern void format_operator_parts(Oid operator_oid, List **objnames, extern void format_operator_parts(Oid operator_oid, List **objnames,
List **objargs); List **objargs, bool missing_ok);
#endif #endif
...@@ -521,3 +521,103 @@ drop cascades to function trig() ...@@ -521,3 +521,103 @@ drop cascades to function trig()
drop cascades to function proc(integer) drop cascades to function proc(integer)
DROP OWNED BY regress_addr_user; DROP OWNED BY regress_addr_user;
DROP USER 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; ...@@ -221,3 +221,67 @@ DROP SCHEMA addr_nsp CASCADE;
DROP OWNED BY regress_addr_user; DROP OWNED BY regress_addr_user;
DROP USER 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment