* 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;
if (schemaname)
{
/* use exact schema given */
- namespaceId = LookupExplicitNamespace(schemaname, false);
+ namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+ if (!OidIsValid(namespaceId))
+ return NULL;
}
else
{
visible = false;
clist = FuncnameGetCandidates(list_make1(makeString(proname)),
- nargs, NIL, false, false);
+ nargs, NIL, false, false, false);
for (; clist; clist = clist->next)
{
* 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)
{
/* 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;
}
* 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);
* 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
* 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,
{
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);
/* 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:
/* 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;
}
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);
address.objectId = InvalidOid;
address.objectSubId = 0;
- tup = LookupTypeName(NULL, typename, NULL);
+ tup = LookupTypeName(NULL, typename, NULL, missing_ok);
if (!HeapTupleIsValid(tup))
{
if (!missing_ok)
ObjectAddress address;
Assert(list_length(objargs) == 1);
+ /* XXX no missing_ok support here */
amoid = get_am_oid(strVal(linitial(objargs)), false);
switch (objtype)
*
*-------------------------------------------------------------------------
*/
-
#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.
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;
}
}
/*
+ * 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)
{
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");
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);
Type typtup;
AclResult aclresult;
- typtup = LookupTypeName(NULL, returnType, NULL);
+ typtup = LookupTypeName(NULL, returnType, NULL, false);
if (typtup)
{
Type typtup;
AclResult aclresult;
- typtup = LookupTypeName(NULL, t, NULL);
+ typtup = LookupTypeName(NULL, t, NULL, false);
if (typtup)
{
if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined)
/* 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
{
/* 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
{
* 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)
{
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;
}
}
/* Not there? */
if (!OidIsValid(relOid))
{
- DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+ DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
continue;
}
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),
/* 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
Oid result;
Type typtup;
- typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL);
+ typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
if (typtup == NULL)
return InvalidOid;
{
FuncCandidateList clist;
- clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false);
+ clist = FuncnameGetCandidates(funcname, nargs, NIL, false, false, noError);
while (clist)
{
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
{
TypeName *t = (TypeName *) lfirst(args_item);
- argoids[i] = LookupTypeNameOid(t);
+ argoids[i] = LookupTypeNameOid(NULL, t, noError);
args_item = lnext(args_item);
}
{
TypeName *t = (TypeName *) lfirst(lc);
- argoids[i] = LookupTypeNameOid(t);
+ argoids[i] = LookupTypeNameOid(NULL, t, noError);
i++;
}
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);
*/
Type
LookupTypeName(ParseState *pstate, const TypeName *typeName,
- int32 *typmod_p)
+ int32 *typmod_p, bool missing_ok)
{
Oid typoid;
HeapTuple tup;
* 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
{
/* 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
{
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
*
{
Type tup;
- tup = LookupTypeName(pstate, typeName, typmod_p);
+ tup = LookupTypeName(pstate, typeName, typmod_p, false);
if (tup == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
* 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,
* 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;
*/
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)
{
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);
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);
* 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);
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();
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);
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
(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';
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();
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);
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;