commit a2de2b402247fded7feba90bf299e91ee14aacca Author: Pavel Stehule Date: Thu Nov 28 08:39:43 2013 +0100 initial diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 9011190..234673f 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -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; } diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c index b32ad3a..191aa17 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,12 @@ static void does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs); +static void prepare_notice_recheck_parent(const char *message, + List *objname, + const char **msg, + char **name, + char **args); + /* * Drop one or more objects. * @@ -125,6 +132,53 @@ 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 +prepare_notice_recheck_parent(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; + } +} + +/* * 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. @@ -201,20 +255,18 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs) (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), - list_length(objname) - 1)); + prepare_notice_recheck_parent("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)); + prepare_notice_recheck_parent("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"); diff --git a/src/test/regress/expected/drop_if_exists.out b/src/test/regress/expected/drop_if_exists.out index 8599401..663b438 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); diff --git a/src/test/regress/sql/drop_if_exists.sql b/src/test/regress/sql/drop_if_exists.sql index 6330566..8977357 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);