drop-if-exists.patch
text/x-patch
Filename: drop-if-exists.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/catalog/namespace.c | 21 | 15 |
| src/backend/catalog/objectaddress.c | 17 | 11 |
| src/backend/commands/dropcmds.c | 170 | 46 |
| src/backend/commands/functioncmds.c | 2 | 2 |
| src/backend/commands/opclasscmds.c | 8 | 5 |
| src/backend/commands/tablecmds.c | 13 | 2 |
| src/backend/commands/typecmds.c | 1 | 1 |
| src/backend/parser/parse_func.c | 6 | 26 |
| src/backend/parser/parse_oper.c | 7 | 7 |
| src/backend/parser/parse_type.c | 52 | 13 |
| src/backend/utils/adt/regproc.c | 4 | 4 |
| src/include/catalog/namespace.h | 3 | 2 |
| src/include/parser/parse_type.h | 3 | 1 |
| src/pl/plpgsql/src/pl_comp.c | 1 | 1 |
| src/test/regress/expected/drop_if_exists.out | 55 | 2 |
| src/test/regress/expected/event_trigger.out | 1 | 1 |
| src/test/regress/sql/drop_if_exists.sql | 31 | 0 |
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 4434dd6..945f757 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -909,7 +909,7 @@ TypeIsVisible(Oid typid)
*/
FuncCandidateList
FuncnameGetCandidates(List *names, int nargs, List *argnames,
- bool expand_variadic, bool expand_defaults)
+ bool expand_variadic, bool expand_defaults, bool noError)
{
FuncCandidateList resultList = NULL;
bool any_special = false;
@@ -928,7 +928,9 @@ FuncnameGetCandidates(List *names, int nargs, List *argnames,
if (schemaname)
{
/* use exact schema given */
- namespaceId = LookupExplicitNamespace(schemaname, false);
+ namespaceId = LookupExplicitNamespace(schemaname, noError);
+ if (!OidIsValid(namespaceId))
+ return NULL;
}
else
{
@@ -1414,7 +1416,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)
{
@@ -1446,7 +1448,7 @@ FunctionIsVisible(Oid funcid)
* namespace search path.
*/
Oid
-OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
+OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError)
{
char *schemaname;
char *opername;
@@ -1462,18 +1464,21 @@ OpernameGetOprid(List *names, Oid oprleft, Oid oprright)
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, noError);
+ if (OidIsValid(namespaceId))
{
- Oid result = HeapTupleGetOid(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;
}
@@ -1734,7 +1739,8 @@ OperatorIsVisible(Oid oprid)
char *oprname = NameStr(oprform->oprname);
visible = (OpernameGetOprid(list_make1(makeString(oprname)),
- oprform->oprleft, oprform->oprright)
+ oprform->oprleft, oprform->oprright,
+ false)
== oprid);
}
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 9011190..6a851fa 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -580,8 +580,8 @@ 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 = LookupTypeNameOid(NULL, sourcetype, missing_ok);
+ Oid targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
address.classId = CastRelationId;
address.objectId =
@@ -942,26 +942,30 @@ 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 != NULL) ? RelationGetRelid(relation) : InvalidOid;
switch (objtype)
{
case OBJECT_RULE:
address.classId = RewriteRelationId;
- address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+ address.objectId = OidIsValid(reloid) ?
+ 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 = OidIsValid(reloid) ?
+ 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 = OidIsValid(reloid) ?
+ get_relation_constraint_oid(reloid, depname, missing_ok) : InvalidOid;
address.objectSubId = 0;
break;
default:
@@ -975,7 +979,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;
}
@@ -1052,7 +1058,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)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..c0e1e25 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -23,6 +23,7 @@
#include "catalog/pg_class.h"
#include "catalog/pg_proc.h"
#include "commands/defrem.h"
+#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "parser/parse_type.h"
@@ -32,6 +33,15 @@
static void does_not_exist_skipping(ObjectType objtype,
List *objname, List *objargs);
+static void parent_not_exist_skipping(const char *message,
+ List *objname,
+ const char **msg,
+ char **name,
+ char **args);
+static bool schema_not_exist_skipping(List *objname,
+ const char **msg, char **name);
+
+
/*
* Drop one or more objects.
*
@@ -125,6 +135,73 @@ RemoveObjects(DropStmt *stmt)
}
/*
+ * Prepare text of "does not exist, skipping" message for triggers and rules,
+ * where we check schema name first, then table name, and as last we raise
+ * message about missing object.
+ */
+static void
+parent_not_exist_skipping(const char *message, List *objname,
+ const char **msg,
+ char **name,
+ char **args)
+{
+ RangeVar *rel;
+
+ rel = makeRangeVarFromNameList(list_truncate(list_copy(objname),
+ list_length(objname) - 1));
+
+ if (rel->schemaname != NULL && !OidIsValid(LookupNamespaceNoError(rel->schemaname)))
+ {
+ *msg = gettext_noop("schema \"%s\" does not exists, skipping");
+ *name = rel->schemaname;
+ *args = NULL;
+ }
+ else if (!OidIsValid(RangeVarGetRelid(rel, NoLock, true)))
+ {
+ *msg = gettext_noop("relation \"%s\" does not exists, skipping");
+ *name = rel->relname;
+ *args = NULL;
+ }
+ else
+ {
+ StringInfoData string;
+
+ *msg = message;
+ *name = strVal(llast(objname));
+
+ initStringInfo(&string);
+ if (rel->schemaname != NULL)
+ {
+ appendStringInfoString(&string, rel->schemaname);
+ appendStringInfoChar(&string, '.');
+ }
+ appendStringInfoString(&string, rel->relname);
+
+ *args = string.data;
+ }
+}
+
+static bool
+schema_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 exists, skipping");
+ *name = rel->schemaname;
+
+ return true;
+ }
+
+ return false;
+}
+
+/*
* 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.
@@ -140,99 +217,146 @@ 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));
- break;
+ if (!schema_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_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_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_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_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_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_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);
+ if (!schema_not_exist_skipping(objname, &msg, &name))
+ {
+ 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_not_exist_skipping(objname, &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_not_exist_skipping(objname, &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_not_exist_skipping(objname, &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)));
+ {
+ TypeName *tobjname = (TypeName *) linitial(objname);
+ TypeName *targname = (TypeName *) linitial(objargs);
+
+ if (!schema_not_exist_skipping(tobjname->names, &msg, &name)
+ && !schema_not_exist_skipping(targname->names, &msg, &name))
+ {
+ msg = gettext_noop("cast from type %s to type %s does not exist, skipping");
+ name = format_type_be(typenameTypeId(NULL, tobjname));
+ args = format_type_be(typenameTypeId(NULL, targname));
+ }
+ }
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),
- list_length(objname) - 1));
+ parent_not_exist_skipping("trigger \"%s\" for table \"%s\" does not exist, skipping",
+ objname,
+ &msg, &name, &args);
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),
- list_length(objname) - 1));
+ parent_not_exist_skipping("rule \"%s\" for relation \"%s\" does not exist, skipping",
+ objname,
+ &msg, &name, &args);
break;
case OBJECT_FDW:
- msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
- name = NameListToString(objname);
+ if (!schema_not_exist_skipping(objname, &msg, &name))
+ {
+ msg = gettext_noop("foreign-data wrapper \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ }
break;
case OBJECT_FOREIGN_SERVER:
msg = gettext_noop("server \"%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_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_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);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ca754b4..348b901 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -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)
{
@@ -220,7 +220,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)
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 3140b37..3f2329b 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -179,11 +179,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
{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3483107..3fc37fe 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -690,10 +690,20 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
* non-existent relation
*/
static void
-DropErrorMsgNonExistent(const char *relname, char rightkind, bool missing_ok)
+DropErrorMsgNonExistent(const char *relname, const char *schemaname, char rightkind, bool missing_ok)
{
const struct dropmsgstrings *rentry;
+ /* schema should be wrong */
+ if (missing_ok && schemaname != NULL &&
+ !OidIsValid(LookupNamespaceNoError(schemaname)))
+ {
+ ereport(NOTICE,
+ (errmsg(gettext_noop("schema \"%s\" does not exists, skipping"),
+ schemaname)));
+ return;
+ }
+
for (rentry = dropmsgstringarray; rentry->kind != '\0'; rentry++)
{
if (rentry->kind == rightkind)
@@ -845,7 +855,8 @@ RemoveRelations(DropStmt *drop)
/* Not there? */
if (!OidIsValid(relOid))
{
- DropErrorMsgNonExistent(rel->relname, relkind, drop->missing_ok);
+ DropErrorMsgNonExistent(rel->relname, rel->schemaname,
+ relkind, drop->missing_ok);
continue;
}
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index d4a14ca..4805f2b 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -3245,7 +3245,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),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index ede36d1..1e57ccb 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -1062,7 +1062,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
@@ -1422,7 +1423,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;
@@ -1581,7 +1582,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)
{
@@ -1601,27 +1602,6 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError)
}
/*
- * 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
* list of TypeName nodes.
@@ -1648,7 +1628,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);
}
@@ -1688,7 +1668,7 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError)
{
TypeName *t = (TypeName *) lfirst(lc);
- argoids[i] = LookupTypeNameOid(t);
+ argoids[i] = LookupTypeNameOid(NULL, t, noError);
i++;
}
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index dd80fa9..9595f10 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -103,7 +103,7 @@ LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
{
Oid result;
- result = OpernameGetOprid(opername, oprleft, oprright);
+ result = OpernameGetOprid(opername, oprleft, oprright, noError);
if (OidIsValid(result))
return result;
@@ -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);
@@ -280,7 +280,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
was_unknown = true;
}
- result = OpernameGetOprid(opname, arg1, arg2);
+ result = OpernameGetOprid(opname, arg1, arg2, false);
if (OidIsValid(result))
return result;
@@ -291,7 +291,7 @@ binary_oper_exact(List *opname, Oid arg1, Oid arg2)
if (basetype != arg1)
{
- result = OpernameGetOprid(opname, basetype, basetype);
+ result = OpernameGetOprid(opname, basetype, basetype, false);
if (OidIsValid(result))
return result;
}
@@ -544,7 +544,7 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
/*
* First try for an "exact" match.
*/
- operOid = OpernameGetOprid(op, arg, InvalidOid);
+ operOid = OpernameGetOprid(op, arg, InvalidOid, noError);
if (!OidIsValid(operOid))
{
/*
@@ -622,7 +622,7 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
/*
* First try for an "exact" match.
*/
- operOid = OpernameGetOprid(op, InvalidOid, arg);
+ operOid = OpernameGetOprid(op, InvalidOid, arg, noError);
if (!OidIsValid(operOid))
{
/*
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ee6802a..c2ce134 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -56,7 +56,8 @@ 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,15 +117,21 @@ 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);
- 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);
+ typoid = InvalidOid;
+ relid = RangeVarGetRelid(rel, NoLock, missing_ok);
+
+ if (OidIsValid(relid))
+ {
+ attnum = get_attnum(relid, field);
+ if (attnum != InvalidAttrNumber)
+ typoid = get_atttype(relid, attnum);
+ else if (!missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ field, rel->relname),
+ parser_errposition(pstate, typeName->location)));
+ }
/* this construct should never have an array indicator */
Assert(typeName->arrayBounds == NIL);
@@ -149,10 +156,13 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
/* Look in specific schema only */
Oid namespaceId;
- namespaceId = LookupExplicitNamespace(schemaname, false);
- typoid = GetSysCacheOid2(TYPENAMENSP,
+ namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
+ if (OidIsValid(namespaceId))
+ typoid = GetSysCacheOid2(TYPENAMENSP,
PointerGetDatum(typname),
ObjectIdGetDatum(namespaceId));
+ else
+ typoid = InvalidOid;
}
else
{
@@ -196,7 +206,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),
@@ -232,6 +242,35 @@ typenameTypeId(ParseState *pstate, const TypeName *typeName)
}
/*
+ * returns oid of type
+ * Convenience routine to look up a type, silently accepting shell types
+ */
+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;
+}
+
+/*
* typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
*
* This is equivalent to typenameType, but we only hand back the type OID
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index c24a2c1..28c1e7f 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -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)
{
@@ -661,7 +661,7 @@ regoperatorin(PG_FUNCTION_ARGS)
errmsg("too many arguments"),
errhint("Provide two argument types for operator.")));
- result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
+ result = OpernameGetOprid(names, argtypes[0], argtypes[1], false);
if (!OidIsValid(result))
ereport(ERROR,
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 4fadc74..05c035b 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -71,10 +71,11 @@ extern bool TypeIsVisible(Oid typid);
extern FuncCandidateList FuncnameGetCandidates(List *names,
int nargs, List *argnames,
bool expand_variadic,
- bool expand_defaults);
+ bool expand_defaults,
+ bool noError);
extern bool FunctionIsVisible(Oid funcid);
-extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright);
+extern Oid OpernameGetOprid(List *names, Oid oprleft, Oid oprright, bool noError);
extern FuncCandidateList OpernameGetCandidates(List *names, char oprkind);
extern bool OperatorIsVisible(Oid oprid);
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 340121a..72505fb 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -20,7 +20,9 @@
typedef HeapTuple Type;
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
- int32 *typmod_p);
+ int32 *typmod_p, bool missing_ok);
+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);
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 426aeb5..692bba4 100644
--- a/src/pl/plpgsql/src/pl_comp.c
+++ b/src/pl/plpgsql/src/pl_comp.c
@@ -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);
diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out
index 8599401..8e37df6 100644
--- a/src/test/regress/expected/drop_if_exists.out
+++ b/src/test/regress/expected/drop_if_exists.out
@@ -173,7 +173,11 @@ NOTICE: trigger "test_trigger_exists" for table "test_exists" does not exist, s
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 exists, 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 exists, 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 exists, 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 exists, 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,48 @@ 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 toleralnt with not existing schema
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP COLLATION IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP CONVERSION IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP DOMAIN IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP FOREIGN TABLE IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP FUNCTION IF EXISTS no_such_schema.foo();
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP INDEX IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP MATERIALIZED VIEW IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP OPERATOR IF EXISTS no_such_schema.+ (int, int);
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP OPERATOR CLASS IF EXISTS no_such_schema.widget_ops USING btree;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP OPERATOR FAMILY IF EXISTS no_such_schema.float_ops USING btree;
+ERROR: schema "no_such_schema" does not exist
+DROP RULE IF EXISTS foo ON no_such_schema.bar;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP SEQUENCE IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TABLE IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH CONFIGURATION IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH DICTIONARY IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH PARSER IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TEXT SEARCH TEMPLATE IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TRIGGER IF EXISTS foo ON no_such_schema.bar;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP TYPE IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
+DROP VIEW IF EXISTS no_such_schema.foo;
+NOTICE: schema "no_such_schema" does not exists, skipping
diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out
index 656d47f..312d89e 100644
--- a/src/test/regress/expected/event_trigger.out
+++ b/src/test/regress/expected/event_trigger.out
@@ -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 exists, 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';
diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql
index 6330566..a2f265d 100644
--- a/src/test/regress/sql/drop_if_exists.sql
+++ b/src/test/regress/sql/drop_if_exists.sql
@@ -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,28 @@ DROP OPERATOR FAMILY IF EXISTS test_operator_family USING no_such_am;
DROP TABLE IF EXISTS test_exists;
DROP TABLE test_exists;
+
+-- be toleralnt with not existing schema
+
+DROP AGGREGATE IF EXISTS no_such_schema.foo(int);
+DROP CAST IF EXISTS (no_such_schema.foo AS no_such_schema.bar);
+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 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 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;