Make DROP IF EXISTS more consistently not fail
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 23 Jan 2014 17:40:29 +0000 (14:40 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 23 Jan 2014 17:40:29 +0000 (14:40 -0300)
Some cases were still reporting errors and aborting, instead of a NOTICE
that the object was being skipped.  This makes it more difficult to
cleanly handle pg_dump --clean, so change that to instead skip missing
objects properly.

Per bug #7873 reported by Dave Rolsky; apparently this affects a large
number of users.

Authors: Pavel Stehule and Dean Rasheed.  Some tweaks by Álvaro Herrera

17 files changed:
src/backend/catalog/namespace.c
src/backend/catalog/objectaddress.c
src/backend/commands/dropcmds.c
src/backend/commands/functioncmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/parser/parse_func.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_type.c
src/backend/utils/adt/regproc.c
src/include/catalog/namespace.h
src/include/parser/parse_type.h
src/pl/plpgsql/src/pl_comp.c
src/test/regress/expected/drop_if_exists.out
src/test/regress/expected/event_trigger.out
src/test/regress/sql/drop_if_exists.sql

index 08b26b462a7b059a86175be7de2e1a9c89929350..6c2a5d2af5aef659e2196210fab535c1324b18c6 100644 (file)
@@ -906,10 +906,15 @@ TypeIsVisible(Oid typid)
  * with oid = 0 that represents a set of such conflicting candidates.
  * The caller might end up discarding such an entry anyway, but if it selects
  * such an entry it should react as though the call were ambiguous.
+ *
+ * If missing_ok is true, an empty list (NULL) is returned if the name was
+ * schema- qualified with a schema that does not exist.  Likewise if no
+ * candidate is found for other reasons.
  */
 FuncCandidateList
 FuncnameGetCandidates(List *names, int nargs, List *argnames,
-                     bool expand_variadic, bool expand_defaults)
+                     bool expand_variadic, bool expand_defaults,
+                     bool missing_ok)
 {
    FuncCandidateList resultList = NULL;
    bool        any_special = false;
@@ -928,7 +933,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
    if (schemaname)
    {
        /* use exact schema given */
-       namespaceId = LookupExplicitNamespace(schemaname, false);
+       namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+       if (!OidIsValid(namespaceId))
+           return NULL;
    }
    else
    {
@@ -1414,7 +1421,7 @@ FunctionIsVisible(Oid funcid)
        visible = false;
 
        clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-                                     nargs, NIL, false, false);
+                                     nargs, NIL, false, false, false);
 
        for (; clist; clist = clist->next)
        {
@@ -1443,7 +1450,8 @@ FunctionIsVisible(Oid funcid)
  * a postfix op.
  *
  * If the operator name is not schema-qualified, it is sought in the current
- * namespace search path.
+ * namespace search path.  If the name is schema-qualified and the given
+ * schema does not exist, InvalidOid is returned.
  */
 Oid
 OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
@@ -1460,21 +1468,26 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
    {
        /* search only in exact schema given */
        Oid         namespaceId;
-       HeapTuple   opertup;
 
-       namespaceId = LookupExplicitNamespace(schemaname, false);
-       opertup = SearchSysCache4(OPERNAMENSP,
-                                 CStringGetDatum(opername),
-                                 ObjectIdGetDatum(oprleft),
-                                 ObjectIdGetDatum(oprright),
-                                 ObjectIdGetDatum(namespaceId));
-       if (HeapTupleIsValid(opertup))
+       namespaceId = LookupExplicitNamespace(schemaname, true);
+       if (OidIsValid(namespaceId))
        {
-           Oid         result = HeapTupleGetOid(opertup);
+           HeapTuple   opertup;
+
+           opertup = SearchSysCache4(OPERNAMENSP,
+                                     CStringGetDatum(opername),
+                                     ObjectIdGetDatum(oprleft),
+                                     ObjectIdGetDatum(oprright),
+                                     ObjectIdGetDatum(namespaceId));
+           if (HeapTupleIsValid(opertup))
+           {
+               Oid         result = HeapTupleGetOid(opertup);
 
-           ReleaseSysCache(opertup);
-           return result;
+               ReleaseSysCache(opertup);
+               return result;
+           }
        }
+
        return InvalidOid;
    }
 
@@ -1729,7 +1742,7 @@ OperatorIsVisible(Oid oprid)
         * If it is in the path, it might still not be visible; it could be
         * hidden by another operator of the same name and arguments earlier
         * in the path.  So we must do a slow check to see if this is the same
-        * operator that would be found by OpernameGetOprId.
+        * operator that would be found by OpernameGetOprid.
         */
        char       *oprname = NameStr(oprform->oprname);
 
index a6ec6aa04bdd952354d9d6c8b7115766fca4d341..ea812238be075e0028a3803a19c38933cff31926 100644 (file)
@@ -450,7 +450,7 @@ static void getRelationIdentity(StringInfo buffer, Oid relid);
  * sub-object is looked up, the parent object will be locked instead.
  *
  * If the object is a relation or a child object of a relation (e.g. an
- * attribute or contraint), the relation is also opened and *relp receives
+ * attribute or constraint), the relation is also opened and *relp receives
  * the open relcache entry pointer; otherwise, *relp is set to NULL.  This
  * is a bit grotty but it makes life simpler, since the caller will
  * typically need the relcache entry too.  Caller must close the relcache
@@ -458,9 +458,20 @@ static void getRelationIdentity(StringInfo buffer, Oid relid);
  * if the target object is the relation itself or an attribute, but for other
  * child objects, only AccessShareLock is acquired on the relation.
  *
+ * If the object is not found, an error is thrown, unless missing_ok is
+ * true.  In this case, no lock is acquired, relp is set to NULL, and the
+ * returned address has objectId set to InvalidOid.
+ *
  * We don't currently provide a function to release the locks acquired here;
  * typically, the lock must be held until commit to guard against a concurrent
  * drop operation.
+ *
+ * Note: If the object is not found, we don't give any indication of the
+ * reason. (It might have been a missing schema if the name was qualified, or
+ * an inexistant type name in case of a cast, function or operator; etc).
+ * Currently there is only one caller that might be interested in such info, so
+ * we don't spend much effort here.  If more callers start to care, it might be
+ * better to add some support for that in this function.
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
@@ -580,9 +591,11 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
                {
                    TypeName   *sourcetype = (TypeName *) linitial(objname);
                    TypeName   *targettype = (TypeName *) linitial(objargs);
-                   Oid         sourcetypeid = typenameTypeId(NULL, sourcetype);
-                   Oid         targettypeid = typenameTypeId(NULL, targettype);
+                   Oid         sourcetypeid;
+                   Oid         targettypeid;
 
+                   sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+                   targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
                    address.classId = CastRelationId;
                    address.objectId =
                        get_cast_oid(sourcetypeid, targettypeid, missing_ok);
@@ -942,26 +955,31 @@ get_object_address_relobject(ObjectType objtype, List *objname,
 
        /* Extract relation name and open relation. */
        relname = list_truncate(list_copy(objname), nnames - 1);
-       relation = heap_openrv(makeRangeVarFromNameList(relname),
-                              AccessShareLock);
-       reloid = RelationGetRelid(relation);
+       relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
+                                       AccessShareLock,
+                                       missing_ok);
+
+       reloid = relation ? RelationGetRelid(relation) : InvalidOid;
 
        switch (objtype)
        {
            case OBJECT_RULE:
                address.classId = RewriteRelationId;
-               address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+               address.objectId = relation ?
+                   get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
                address.objectSubId = 0;
                break;
            case OBJECT_TRIGGER:
                address.classId = TriggerRelationId;
-               address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+               address.objectId = relation ?
+                   get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
                address.objectSubId = 0;
                break;
            case OBJECT_CONSTRAINT:
                address.classId = ConstraintRelationId;
-               address.objectId =
-                   get_relation_constraint_oid(reloid, depname, missing_ok);
+               address.objectId = relation ?
+                   get_relation_constraint_oid(reloid, depname, missing_ok) :
+                   InvalidOid;
                address.objectSubId = 0;
                break;
            default:
@@ -975,7 +993,9 @@ get_object_address_relobject(ObjectType objtype, List *objname,
        /* Avoid relcache leak when object not found. */
        if (!OidIsValid(address.objectId))
        {
-           heap_close(relation, AccessShareLock);
+           if (relation != NULL)
+               heap_close(relation, AccessShareLock);
+
            relation = NULL;    /* department of accident prevention */
            return address;
        }
@@ -1008,6 +1028,7 @@ get_object_address_attribute(ObjectType objtype, List *objname,
                 errmsg("column name must be qualified")));
    attname = strVal(lfirst(list_tail(objname)));
    relname = list_truncate(list_copy(objname), list_length(objname) - 1);
+   /* XXX no missing_ok support here */
    relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
    reloid = RelationGetRelid(relation);
 
@@ -1053,7 +1074,7 @@ get_object_address_type(ObjectType objtype,
    address.objectId = InvalidOid;
    address.objectSubId = 0;
 
-   tup = LookupTypeName(NULL, typename, NULL);
+   tup = LookupTypeName(NULL, typename, NULL, missing_ok);
    if (!HeapTupleIsValid(tup))
    {
        if (!missing_ok)
@@ -1090,6 +1111,7 @@ get_object_address_opcf(ObjectType objtype,
    ObjectAddress address;
 
    Assert(list_length(objargs) == 1);
+   /* XXX no missing_ok support here */
    amoid = get_am_oid(strVal(linitial(objargs)), false);
 
    switch (objtype)
index b25317ebad427b7cc8f16f2cb49669ccce28d4a3..e64ad8027e22f9455063b6b9b87b74edee9109ba 100644 (file)
@@ -12,7 +12,6 @@
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
 
 #include "access/heapam.h"
 #include "utils/builtins.h"
 #include "utils/syscache.h"
 
+
 static void does_not_exist_skipping(ObjectType objtype,
                        List *objname, List *objargs);
+static bool owningrel_does_not_exist_skipping(List *objname,
+                                 const char **msg, char **name);
+static bool schema_does_not_exist_skipping(List *objname,
+                              const char **msg, char **name);
+static bool type_in_list_does_not_exist_skipping(List *typenames,
+                                    const char **msg, char **name);
+
 
 /*
  * Drop one or more objects.
@@ -73,9 +80,14 @@ RemoveObjects(DropStmt *stmt)
                                     AccessExclusiveLock,
                                     stmt->missing_ok);
 
-       /* Issue NOTICE if supplied object was not found. */
+       /*
+        * Issue NOTICE if supplied object was not found.  Note this is only
+        * relevant in the missing_ok case, because otherwise
+        * get_object_address would have thrown an error.
+        */
        if (!OidIsValid(address.objectId))
        {
+           Assert(stmt->missing_ok);
            does_not_exist_skipping(stmt->removeType, objname, objargs);
            continue;
        }
@@ -125,9 +137,121 @@ RemoveObjects(DropStmt *stmt)
 }
 
 /*
+ * owningrel_does_not_exist_skipping
+ *     Subroutine for RemoveObjects
+ *
+ * After determining that a specification for a rule or trigger returns that
+ * the specified object does not exist, test whether its owning relation, and
+ * its schema, exist or not; if they do, return false --- the trigger or rule
+ * itself is missing instead.  If the owning relation or its schema do not
+ * exist, fill the error message format string and name, and return true.
+ */
+static bool
+owningrel_does_not_exist_skipping(List *objname, const char **msg, char **name)
+{
+   List       *parent_objname;
+   RangeVar   *parent_rel;
+
+   parent_objname = list_truncate(list_copy(objname),
+                                  list_length(objname) - 1);
+
+   if (schema_does_not_exist_skipping(parent_objname, msg, name))
+       return true;
+
+   parent_rel = makeRangeVarFromNameList(parent_objname);
+
+   if (!OidIsValid(RangeVarGetRelid(parent_rel, NoLock, true)))
+   {
+       *msg = gettext_noop("relation \"%s\" does not exist, skipping");
+       *name = NameListToString(parent_objname);
+
+       return true;
+   }
+
+   return false;
+}
+
+/*
+ * schema_does_not_exist_skipping
+ *     Subroutine for RemoveObjects
+ *
+ * After determining that a specification for a schema-qualifiable object
+ * refers to an object that does not exist, test whether the specified schema
+ * exists or not.  If no schema was specified, or if the schema does exist,
+ * return false -- the object itself is missing instead.  If the specified
+ * schema does not exist, fill the error message format string and the
+ * specified schema name, and return true.
+ */
+static bool
+schema_does_not_exist_skipping(List *objname, const char **msg, char **name)
+{
+   RangeVar   *rel;
+
+   rel = makeRangeVarFromNameList(objname);
+
+   if (rel->schemaname != NULL &&
+       !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+   {
+       *msg = gettext_noop("schema \"%s\" does not exist, skipping");
+       *name = rel->schemaname;
+
+       return true;
+   }
+
+   return false;
+}
+
+/*
+ * type_in_list_does_not_exist_skipping
+ *     Subroutine for RemoveObjects
+ *
+ * After determining that a specification for a function, cast, aggregate or
+ * operator returns that the specified object does not exist, test whether the
+ * involved datatypes, and their schemas, exist or not; if they do, return
+ * false --- the original object itself is missing instead.  If the datatypes
+ * or schemas do not exist, fill the error message format string and the
+ * missing name, and return true.
+ *
+ * First parameter is a list of TypeNames.
+ */
+static bool
+type_in_list_does_not_exist_skipping(List *typenames, const char **msg,
+                                    char **name)
+{
+   ListCell   *l;
+
+   foreach(l, typenames)
+   {
+       TypeName   *typeName = (TypeName *) lfirst(l);
+
+       if (typeName != NULL)
+       {
+           Assert(IsA(typeName, TypeName));
+
+           if (!OidIsValid(LookupTypeNameOid(NULL, typeName, true)))
+           {
+               /* type doesn't exist, try to find why */
+               if (schema_does_not_exist_skipping(typeName->names, msg, name))
+                   return true;
+
+               *msg = gettext_noop("type \"%s\" does not exist, skipping");
+               *name = TypeNameToString(typeName);
+
+               return true;
+           }
+       }
+   }
+
+   return false;
+}
+
+/*
+ * does_not_exist_skipping
+ *     Subroutine for RemoveObjects
+ *
  * Generate a NOTICE stating that the named object was not found, and is
  * being skipped.  This is only relevant when "IF EXISTS" is used; otherwise,
- * get_object_address() will throw an ERROR.
+ * get_object_address() in RemoveObjects would have thrown an ERROR.
  */
 static void
 does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
@@ -140,81 +264,125 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
    {
        case OBJECT_TYPE:
        case OBJECT_DOMAIN:
-           msg = gettext_noop("type \"%s\" does not exist, skipping");
-           name = TypeNameToString(makeTypeNameFromNameList(objname));
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("type \"%s\" does not exist, skipping");
+               name = TypeNameToString(makeTypeNameFromNameList(objname));
+           }
            break;
        case OBJECT_COLLATION:
-           msg = gettext_noop("collation \"%s\" does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("collation \"%s\" does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_CONVERSION:
-           msg = gettext_noop("conversion \"%s\" does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("conversion \"%s\" does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_SCHEMA:
            msg = gettext_noop("schema \"%s\" does not exist, skipping");
            name = NameListToString(objname);
            break;
        case OBJECT_TSPARSER:
-           msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("text search parser \"%s\" does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_TSDICTIONARY:
-           msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("text search dictionary \"%s\" does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_TSTEMPLATE:
-           msg = gettext_noop("text search template \"%s\" does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("text search template \"%s\" does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_TSCONFIGURATION:
-           msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("text search configuration \"%s\" does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_EXTENSION:
            msg = gettext_noop("extension \"%s\" does not exist, skipping");
            name = NameListToString(objname);
            break;
        case OBJECT_FUNCTION:
-           msg = gettext_noop("function %s(%s) does not exist, skipping");
-           name = NameListToString(objname);
-           args = TypeNameListToString(objargs);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name) &&
+               !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+           {
+               msg = gettext_noop("function %s(%s) does not exist, skipping");
+               name = NameListToString(objname);
+               args = TypeNameListToString(objargs);
+           }
            break;
        case OBJECT_AGGREGATE:
-           msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
-           name = NameListToString(objname);
-           args = TypeNameListToString(objargs);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name) &&
+               !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+           {
+               msg = gettext_noop("aggregate %s(%s) does not exist, skipping");
+               name = NameListToString(objname);
+               args = TypeNameListToString(objargs);
+           }
            break;
        case OBJECT_OPERATOR:
-           msg = gettext_noop("operator %s does not exist, skipping");
-           name = NameListToString(objname);
+           if (!schema_does_not_exist_skipping(objname, &msg, &name) &&
+               !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+           {
+               msg = gettext_noop("operator %s does not exist, skipping");
+               name = NameListToString(objname);
+           }
            break;
        case OBJECT_LANGUAGE:
            msg = gettext_noop("language \"%s\" does not exist, skipping");
            name = NameListToString(objname);
            break;
        case OBJECT_CAST:
-           msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
-           name = format_type_be(typenameTypeId(NULL,
-                                           (TypeName *) linitial(objname)));
-           args = format_type_be(typenameTypeId(NULL,
-                                           (TypeName *) linitial(objargs)));
+           {
+               if (!type_in_list_does_not_exist_skipping(objname, &msg, &name) &&
+                !type_in_list_does_not_exist_skipping(objargs, &msg, &name))
+               {
+                   /* XXX quote or no quote? */
+                   msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+                   name = TypeNameToString((TypeName *) linitial(objname));
+                   args = TypeNameToString((TypeName *) linitial(objargs));
+               }
+           }
            break;
        case OBJECT_TRIGGER:
-           msg = gettext_noop("trigger \"%s\" for table \"%s\" does not exist, skipping");
-           name = strVal(llast(objname));
-           args = NameListToString(list_truncate(list_copy(objname),
+           if (!owningrel_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("trigger \"%s\" for relation \"%s\" does not exist, skipping");
+               name = strVal(llast(objname));
+               args = NameListToString(list_truncate(list_copy(objname),
                                                  list_length(objname) - 1));
+           }
            break;
        case OBJECT_EVENT_TRIGGER:
            msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
            name = NameListToString(objname);
            break;
        case OBJECT_RULE:
-           msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
-           name = strVal(llast(objname));
-           args = NameListToString(list_truncate(list_copy(objname),
+           if (!owningrel_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("rule \"%s\" for relation \"%s\" does not exist, skipping");
+               name = strVal(llast(objname));
+               args = NameListToString(list_truncate(list_copy(objname),
                                                  list_length(objname) - 1));
+           }
            break;
        case OBJECT_FDW:
            msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
@@ -225,14 +393,20 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
            name = NameListToString(objname);
            break;
        case OBJECT_OPCLASS:
-           msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
-           name = NameListToString(objname);
-           args = strVal(linitial(objargs));
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("operator class \"%s\" does not exist for access method \"%s\", skipping");
+               name = NameListToString(objname);
+               args = strVal(linitial(objargs));
+           }
            break;
        case OBJECT_OPFAMILY:
-           msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
-           name = NameListToString(objname);
-           args = strVal(linitial(objargs));
+           if (!schema_does_not_exist_skipping(objname, &msg, &name))
+           {
+               msg = gettext_noop("operator family \"%s\" does not exist for access method \"%s\", skipping");
+               name = NameListToString(objname);
+               args = strVal(linitial(objargs));
+           }
            break;
        default:
            elog(ERROR, "unexpected object type (%d)", (int) objtype);
index 7763feccf9703ff64e177232428d4b9526013032..350cb76ab8cfd5f001f7e5426570f04d8d7de823 100644 (file)
@@ -86,7 +86,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
    Type        typtup;
    AclResult   aclresult;
 
-   typtup = LookupTypeName(NULL, returnType, NULL);
+   typtup = LookupTypeName(NULL, returnType, NULL, false);
 
    if (typtup)
    {
@@ -224,7 +224,7 @@ interpret_function_parameter_list(List *parameters,
        Type        typtup;
        AclResult   aclresult;
 
-       typtup = LookupTypeName(NULL, t, NULL);
+       typtup = LookupTypeName(NULL, t, NULL, false);
        if (typtup)
        {
            if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
index c910c3964c60b9ac01760df37a5626e55fa80326..5d7b37c674ad24e41ceee21860ab6e719cb9f89b 100644 (file)
@@ -103,11 +103,14 @@ OpFamilyCacheLookup(Oid amID, List *opfamilyname, bool missing_ok)
        /* Look in specific schema only */
        Oid         namespaceId;
 
-       namespaceId = LookupExplicitNamespace(schemaname, false);
-       htup = SearchSysCache3(OPFAMILYAMNAMENSP,
-                              ObjectIdGetDatum(amID),
-                              PointerGetDatum(opfname),
-                              ObjectIdGetDatum(namespaceId));
+       namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+       if (!OidIsValid(namespaceId))
+           htup = NULL;
+       else
+           htup = SearchSysCache3(OPFAMILYAMNAMENSP,
+                                  ObjectIdGetDatum(amID),
+                                  PointerGetDatum(opfname),
+                                  ObjectIdGetDatum(namespaceId));
    }
    else
    {
@@ -179,11 +182,14 @@ OpClassCacheLookup(Oid amID, List *opclassname, bool missing_ok)
        /* Look in specific schema only */
        Oid         namespaceId;
 
-       namespaceId = LookupExplicitNamespace(schemaname, false);
-       htup = SearchSysCache3(CLAAMNAMENSP,
-                              ObjectIdGetDatum(amID),
-                              PointerGetDatum(opcname),
-                              ObjectIdGetDatum(namespaceId));
+       namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+       if (!OidIsValid(namespaceId))
+           htup = NULL;
+       else
+           htup = SearchSysCache3(CLAAMNAMENSP,
+                                  ObjectIdGetDatum(amID),
+                                  PointerGetDatum(opcname),
+                                  ObjectIdGetDatum(namespaceId));
    }
    else
    {
index 26a4613c47438d854022a7f78c0178b460d04d44..08b037e501f36295c34ee59f29f234c2472643ee 100644 (file)
@@ -690,10 +690,28 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
  * non-existent relation
  */
 static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(RangeVar *rel, char rightkind, bool missing_ok)
 {
    const struct dropmsgstrings *rentry;
 
+   if (rel->schemaname != NULL &&
+       !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+   {
+       if (!missing_ok)
+       {
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_SCHEMA),
+                    errmsg("schema \"%s\" does not exist", rel->schemaname)));
+       }
+       else
+       {
+           ereport(NOTICE,
+                   (errmsg("schema \"%s\" does not exist, skipping",
+                           rel->schemaname)));
+       }
+       return;
+   }
+
    for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
    {
        if (rentry->kind == rightkind)
@@ -702,11 +720,11 @@ DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
            {
                ereport(ERROR,
                        (errcode(rentry->nonexistent_code),
-                        errmsg(rentry->nonexistent_msg, relname)));
+                        errmsg(rentry->nonexistent_msg, rel->relname)));
            }
            else
            {
-               ereport(NOTICE, (errmsg(rentry->skipping_msg, relname)));
+               ereport(NOTICE, (errmsg(rentry->skipping_msg, rel->relname)));
                break;
            }
        }
@@ -845,7 +863,7 @@ RemoveRelations(DropStmt *drop)
        /* Not there? */
        if (!OidIsValid(relOid))
        {
-           DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+           DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
            continue;
        }
 
index d85c16c7270f618e9e18ae1e5c7b9c0db89bc9a0..c1ee69b32336806facf5a30a1c0d5f265c1940ae 100644 (file)
@@ -3246,7 +3246,7 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
    typename = makeTypeNameFromNameList(names);
 
    /* Use LookupTypeName here so that shell types can be processed */
-   tup = LookupTypeName(NULL, typename, NULL);
+   tup = LookupTypeName(NULL, typename, NULL, false);
    if (tup == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
index 32179aacb55d5953cbfaec4effb23a384a65ac20..63be2a44f16ea7755e55b3ab7be1f238d69427d2 100644 (file)
@@ -1259,7 +1259,8 @@ func_get_detail(List *funcname,
 
    /* Get list of possible candidates from namespace search */
    raw_candidates = FuncnameGetCandidates(funcname, nargs, fargnames,
-                                          expand_variadic, expand_defaults);
+                                          expand_variadic, expand_defaults,
+                                          false);
 
    /*
     * Quickly check if there is an exact match to the input datatypes (there
@@ -1714,7 +1715,7 @@ FuncNameAsType(List *funcname)
    Oid         result;
    Type        typtup;
 
-   typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+   typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
    if (typtup == NULL)
        return InvalidOid;
 
@@ -1873,7 +1874,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
 {
    FuncCandidateList clist;
 
-   clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+   clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
 
    while (clist)
    {
@@ -1892,27 +1893,6 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
    return InvalidOid;
 }
 
-/*
- * LookupTypeNameOid
- *     Convenience routine to look up a type, silently accepting shell types
- */
-static Oid
-LookupTypeNameOid(const TypeName *typename)
-{
-   Oid         result;
-   Type        typtup;
-
-   typtup = LookupTypeName(NULL, typename, NULL);
-   if (typtup == NULL)
-       ereport(ERROR,
-               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                errmsg("type \"%s\" does not exist",
-                       TypeNameToString(typename))));
-   result = typeTypeId(typtup);
-   ReleaseSysCache(typtup);
-   return result;
-}
-
 /*
  * LookupFuncNameTypeNames
  *     Like LookupFuncName, but the argument types are specified by a
@@ -1940,7 +1920,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
    {
        TypeName   *t = (TypeName *) lfirst(args_item);
 
-       argoids[i] = LookupTypeNameOid(t);
+       argoids[i] = LookupTypeNameOid(NULL, t, noError);
        args_item = lnext(args_item);
    }
 
@@ -1980,7 +1960,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
    {
        TypeName   *t = (TypeName *) lfirst(lc);
 
-       argoids[i] = LookupTypeNameOid(t);
+       argoids[i] = LookupTypeNameOid(NULL, t, noError);
        i++;
    }
 
index 387f7fd0b36f8ed57da8e0fb9f393bea35134bc9..99dbd30d758b564b4de6ab255765d06bc49ece28 100644 (file)
@@ -148,12 +148,12 @@ LookupOperNameTypeNames(ParseState *pstate, List *opername,
    if (oprleft == NULL)
        leftoid = InvalidOid;
    else
-       leftoid = typenameTypeId(pstate, oprleft);
+       leftoid = LookupTypeNameOid(pstate, oprleft, noError);
 
    if (oprright == NULL)
        rightoid = InvalidOid;
    else
-       rightoid = typenameTypeId(pstate, oprright);
+       rightoid = LookupTypeNameOid(pstate, oprright, noError);
 
    return LookupOperName(pstate, opername, leftoid, rightoid,
                          noError, location);
index 635aa1d3631c53e8a3d073cb3f660ed5a53556b7..b329dfb168493ccdb61636cb023c501ab9dd661e 100644 (file)
@@ -56,7 +56,7 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
  */
 Type
 LookupTypeName(ParseState *pstate, const TypeName *typeName,
-              int32 *typmod_p)
+              int32 *typmod_p, bool missing_ok)
 {
    Oid         typoid;
    HeapTuple   tup;
@@ -116,24 +116,32 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
         * concurrent DDL.  But taking a lock would carry a performance
         * penalty and would also require a permissions check.
         */
-       relid = RangeVarGetRelid(rel, NoLock, false);
+       relid = RangeVarGetRelid(rel, NoLock, missing_ok);
        attnum = get_attnum(relid, field);
        if (attnum == InvalidAttrNumber)
-           ereport(ERROR,
-                   (errcode(ERRCODE_UNDEFINED_COLUMN),
-                    errmsg("column \"%s\" of relation \"%s\" does not exist",
-                           field, rel->relname),
-                    parser_errposition(pstate, typeName->location)));
-       typoid = get_atttype(relid, attnum);
+       {
+           if (missing_ok)
+               typoid = InvalidOid;
+           else
+               ereport(ERROR,
+                       (errcode(ERRCODE_UNDEFINED_COLUMN),
+                   errmsg("column \"%s\" of relation \"%s\" does not exist",
+                          field, rel->relname),
+                        parser_errposition(pstate, typeName->location)));
+       }
+       else
+       {
+           typoid = get_atttype(relid, attnum);
 
-       /* this construct should never have an array indicator */
-       Assert(typeName->arrayBounds == NIL);
+           /* this construct should never have an array indicator */
+           Assert(typeName->arrayBounds == NIL);
 
-       /* emit nuisance notice (intentionally not errposition'd) */
-       ereport(NOTICE,
-               (errmsg("type reference %s converted to %s",
-                       TypeNameToString(typeName),
-                       format_type_be(typoid))));
+           /* emit nuisance notice (intentionally not errposition'd) */
+           ereport(NOTICE,
+                   (errmsg("type reference %s converted to %s",
+                           TypeNameToString(typeName),
+                           format_type_be(typoid))));
+       }
    }
    else
    {
@@ -149,10 +157,13 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
            /* Look in specific schema only */
            Oid         namespaceId;
 
-           namespaceId = LookupExplicitNamespace(schemaname, false);
-           typoid = GetSysCacheOid2(TYPENAMENSP,
-                                    PointerGetDatum(typname),
-                                    ObjectIdGetDatum(namespaceId));
+           namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+           if (OidIsValid(namespaceId))
+               typoid = GetSysCacheOid2(TYPENAMENSP,
+                                        PointerGetDatum(typname),
+                                        ObjectIdGetDatum(namespaceId));
+           else
+               typoid = InvalidOid;
        }
        else
        {
@@ -184,6 +195,43 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
    return (Type) tup;
 }
 
+/*
+ * LookupTypeNameOid
+ *     Given a TypeName object, lookup the pg_type syscache entry of the type.
+ *     Returns InvalidOid if no such type can be found.  If the type is found,
+ *     return its Oid.
+ *
+ * NB: direct callers of this function need to be aware that the type OID
+ * returned may correspond to a shell type.  Most code should go through
+ * typenameTypeId instead.
+ *
+ * pstate is only used for error location info, and may be NULL.
+ */
+Oid
+LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
+{
+   Oid         typoid;
+   Type        tup;
+
+   tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
+   if (tup == NULL)
+   {
+       if (!missing_ok)
+           ereport(ERROR,
+                   (errcode(ERRCODE_UNDEFINED_OBJECT),
+                    errmsg("type \"%s\" does not exist",
+                           TypeNameToString(typeName)),
+                    parser_errposition(pstate, typeName->location)));
+
+       return InvalidOid;
+   }
+
+   typoid = HeapTupleGetOid(tup);
+   ReleaseSysCache(tup);
+
+   return typoid;
+}
+
 /*
  * typenameType - given a TypeName, return a Type structure and typmod
  *
@@ -196,7 +244,7 @@ typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
 {
    Type        tup;
 
-   tup = LookupTypeName(pstate, typeName, typmod_p);
+   tup = LookupTypeName(pstate, typeName, typmod_p, false);
    if (tup == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
index 5023d163a505acaac4e927b333d5e86d1e2b895f..5d73562a4fc324b9028de329fae59168eca845f5 100644 (file)
@@ -135,7 +135,7 @@ regprocin(PG_FUNCTION_ARGS)
     * pg_proc entries in the current search path.
     */
    names = stringToQualifiedNameList(pro_name_or_oid);
-   clist = FuncnameGetCandidates(names, -1, NIL, false, false);
+   clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
 
    if (clist == NULL)
        ereport(ERROR,
@@ -192,7 +192,7 @@ regprocout(PG_FUNCTION_ARGS)
             * qualify it.
             */
            clist = FuncnameGetCandidates(list_make1(makeString(proname)),
-                                         -1, NIL, false, false);
+                                         -1, NIL, false, false, false);
            if (clist != NULL && clist->next == NULL &&
                clist->oid == proid)
                nspname = NULL;
@@ -279,7 +279,7 @@ regprocedurein(PG_FUNCTION_ARGS)
     */
    parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
 
-   clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
+   clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
 
    for (; clist; clist = clist->next)
    {
index 810ffa3be1780a429b6fc73824928658d11f179c..b30e5e8d02544c4afcfecfd97343951b0c6e3a91 100644 (file)
@@ -71,7 +71,8 @@ extern bool TypeIsVisible(Oid typid);
 extern FuncCandidateList FuncnameGetCandidates(List *names,
                      int nargs, List *argnames,
                      bool expand_variadic,
-                     bool expand_defaults);
+                     bool expand_defaults,
+                     bool missing_ok);
 extern bool FunctionIsVisible(Oid funcid);
 
 extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
index 9208bad26d7f6e832144312c4a40e0723b2125a9..ab73148dcaadc32d231d6eb0c3d53b6288ec418e 100644 (file)
@@ -20,7 +20,9 @@
 typedef HeapTuple Type;
 
 extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
-              int32 *typmod_p);
+              int32 *typmod_p, bool missing_ok);
+extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
+                 bool missing_ok);
 extern Type typenameType(ParseState *pstate, const TypeName *typeName,
             int32 *typmod_p);
 extern Oid typenameTypeId(ParseState *pstate, const TypeName *typeName);
index 05cd1710584cbc11710b2891bfd04710daefbc3b..5afc2e500441c935e755b29bedb5b8e0271aed4d 100644 (file)
@@ -1665,7 +1665,7 @@ plpgsql_parse_wordtype(char *ident)
     * Word wasn't found in the namespace stack. Try to find a data type with
     * that name, but ignore shell types and complex types.
     */
-   typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL);
+   typeTup = LookupTypeName(NULL, makeTypeName(ident), NULL, false);
    if (typeTup)
    {
        Form_pg_type typeStruct = (Form_pg_type) GETSTRUCT(typeTup);
index 85994016e156d0824d9a2df61a85989575039393..6910b627c1538d16f86c2daa9981c4a5c5ba5c75 100644 (file)
@@ -169,11 +169,15 @@ NOTICE:  cast from type text to type text does not exist, skipping
 DROP TRIGGER test_trigger_exists ON test_exists;
 ERROR:  trigger "test_trigger_exists" for table "test_exists" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
-NOTICE:  trigger "test_trigger_exists" for table "test_exists" does not exist, skipping
+NOTICE:  trigger "test_trigger_exists" for relation "test_exists" does not exist, skipping
 DROP TRIGGER test_trigger_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -186,7 +190,11 @@ NOTICE:  rule "test_rule_exists" for relation "test_exists" does not exist, skip
 DROP RULE test_rule_exists ON no_such_table;
 ERROR:  relation "no_such_table" does not exist
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
-ERROR:  relation "no_such_table" does not exist
+NOTICE:  relation "no_such_table" does not exist, skipping
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+ERROR:  schema "no_such_schema" does not exist
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+NOTICE:  schema "no_such_schema" does not exist, skipping
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -223,3 +231,68 @@ ERROR:  access method "no_such_am" does not exist
 DROP TABLE IF EXISTS test_exists;
 DROP TABLE test_exists;
 ERROR:  table "test_exists" does not exist
+-- be tolerant with missing schemas, types, etc
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP AGGREGATE IF EXISTS foo(no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CAST IF EXISTS (INTEGER AS no_such_type2);
+NOTICE:  type "no_such_type2" does not exist, skipping
+DROP CAST IF EXISTS (no_such_type1 AS INTEGER);
+NOTICE:  type "no_such_type1" does not exist, skipping
+DROP CAST IF EXISTS (INTEGER AS no_such_schema.bar);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS INTEGER);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP FUNCTION IF EXISTS foo(no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS + (no_such_type, no_such_type);
+NOTICE:  type "no_such_type" does not exist, skipping
+DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR IF EXISTS # (NONE, no_such_schema.no_such_type);
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE:  schema "no_such_schema" does not exist, skipping
index 656d47f9966fd76c5294458ba0b3981edff44b2e..d4723b223d7400f4765efcd83f8ce05eb47547fb 100644 (file)
@@ -280,7 +280,7 @@ SELECT * FROM dropped_objects WHERE schema IS NULL OR schema <> 'pg_toast';
 (23 rows)
 
 DROP OWNED BY regression_bob;
-NOTICE:  table "audit_tbls_schema_one_table_two" does not exist, skipping
+NOTICE:  schema "audit_tbls" does not exist, skipping
 CONTEXT:  SQL statement "DROP TABLE IF EXISTS audit_tbls.audit_tbls_schema_one_table_two"
 PL/pgSQL function test_evtrig_dropped_objects() line 8 at EXECUTE statement
 SELECT * FROM dropped_objects WHERE type = 'schema';
index 633056619aa7158ee05fcea3ffd5b18f1f10c247..03547ccae7a627b2068e738e5757b5f9d8ef0941 100644 (file)
@@ -182,6 +182,9 @@ DROP TRIGGER IF EXISTS test_trigger_exists ON test_exists;
 DROP TRIGGER test_trigger_exists ON no_such_table;
 DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_table;
 
+DROP TRIGGER test_trigger_exists ON no_such_schema.no_such_table;
+DROP TRIGGER IF EXISTS test_trigger_exists ON no_such_schema.no_such_table;
+
 CREATE TRIGGER test_trigger_exists
     BEFORE UPDATE ON test_exists
     FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
@@ -194,6 +197,9 @@ DROP RULE IF EXISTS test_rule_exists ON test_exists;
 DROP RULE test_rule_exists ON no_such_table;
 DROP RULE IF EXISTS test_rule_exists ON no_such_table;
 
+DROP RULE test_rule_exists ON no_such_schema.no_such_table;
+DROP RULE IF EXISTS test_rule_exists ON no_such_schema.no_such_table;
+
 CREATE RULE test_rule_exists AS ON INSERT TO test_exists
     DO INSTEAD
     INSERT INTO test_exists VALUES (NEW.a, NEW.b || NEW.a::text);
@@ -226,3 +232,38 @@ DROP OPERATOR FAMILY IF EXISTS test_operator_family USING no_such_am;
 DROP TABLE IF EXISTS test_exists;
 
 DROP TABLE test_exists;
+
+-- be tolerant with missing schemas, types, etc
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP AGGREGATE IF EXISTS foo(no_such_type);
+DROP AGGREGATE IF EXISTS foo(no_such_schema.no_such_type);
+DROP CAST IF EXISTS (INTEGER AS no_such_type2);
+DROP CAST IF EXISTS (no_such_type1 AS INTEGER);
+DROP CAST IF EXISTS (INTEGER AS no_such_schema.bar);
+DROP CAST IF EXISTS (no_such_schema.foo AS INTEGER);
+DROP COLLATION IF EXISTS no_such_schema.foo;
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+DROP FUNCTION IF EXISTS foo(no_such_type);
+DROP FUNCTION IF EXISTS foo(no_such_schema.no_such_type);
+DROP INDEX IF EXISTS no_such_schema.foo;
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+DROP OPERATOR IF EXISTS + (no_such_type, no_such_type);
+DROP OPERATOR IF EXISTS + (no_such_schema.no_such_type, no_such_schema.no_such_type);
+DROP OPERATOR IF EXISTS # (NONE, no_such_schema.no_such_type);
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+DROP TABLE IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+DROP TYPE IF EXISTS no_such_schema.foo;
+DROP VIEW IF EXISTS no_such_schema.foo;