drop-trigger-if-exists.patch
text/x-patch
Filename: drop-trigger-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/objectaddress.c | 14 | 8 |
| src/backend/commands/dropcmds.c | 60 | 8 |
| src/test/regress/expected/drop_if_exists.out | 10 | 2 |
| src/test/regress/sql/drop_if_exists.sql | 6 | 0 |
commit a2de2b402247fded7feba90bf299e91ee14aacca
Author: Pavel Stehule <pavel.stehule@gooddata.com>
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);