Hello

here is patch with fault tolerant drop trigger and drop rule support

drop trigger [if exists] trgname on [if exists] tablename;
drop rule [if exists] trgname on [if exists] tablename;

Regards

Pavel



2013/11/11 Pavel Stehule <pavel.steh...@gmail.com>

>
>
>
> 2013/11/11 Tom Lane <t...@sss.pgh.pa.us>
>
>> Andres Freund <and...@2ndquadrant.com> writes:
>> > Turns out that's bogus - ALTER TABLE has two levels of NOT EXISTS.
>>
>> > Maybe we should just do the same for DROP TRIGGER?
>>
>> > DROP TRIGGER [ IF EXISTS ] name ON table_name [ IF EXISTS ] [ CASCADE |
>> RESTRICT ]
>>
>> Works for me.
>>
>
> for me too
>
> tomorrow I'll prepare patch
>
> Regards
>
> Pavel
>
>
>>
>>                         regards, tom lane
>>
>>
>> --
>> Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
>> To make changes to your subscription:
>> http://www.postgresql.org/mailpref/pgsql-hackers
>>
>
>
diff --git a/doc/src/sgml/ref/drop_rule.sgml b/doc/src/sgml/ref/drop_rule.sgml
index c845872..585f67b 100644
--- a/doc/src/sgml/ref/drop_rule.sgml
+++ b/doc/src/sgml/ref/drop_rule.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-DROP RULE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
+DROP RULE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON [ IF EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -42,8 +42,8 @@ DROP RULE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON <re
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the rule does not exist. A notice is issued
-      in this case.
+      Do not throw an error if the rule does not exist (or if a parent table
+      does not exist). A notice is issued in this case.
      </para>
     </listitem>
    </varlistentry>
diff --git a/doc/src/sgml/ref/drop_trigger.sgml b/doc/src/sgml/ref/drop_trigger.sgml
index 3ec6cc7..1f46eff 100644
--- a/doc/src/sgml/ref/drop_trigger.sgml
+++ b/doc/src/sgml/ref/drop_trigger.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
+DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON  [ IF EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -44,8 +44,8 @@ DROP TRIGGER [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable> ON
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the trigger does not exist. A notice is issued
-      in this case.
+      Do not throw an error if the trigger does not exist (or parent table
+      does not exist). A notice is issued in this case.
      </para>
     </listitem>
    </varlistentry>
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index cecddf1..36ef9ae 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -423,7 +423,8 @@ static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
 							   List *objname, Relation *relp,
 							   LOCKMODE lockmode, bool missing_ok);
 static ObjectAddress get_object_address_relobject(ObjectType objtype,
-							 List *objname, Relation *relp, bool missing_ok);
+							 List *objname, Relation *relp,
+							 bool missing_ok, bool missing_parent_ok);
 static ObjectAddress get_object_address_attribute(ObjectType objtype,
 							 List *objname, Relation *relp,
 							 LOCKMODE lockmode, bool missing_ok);
@@ -464,7 +465,8 @@ static void getRelationIdentity(StringInfo buffer, Oid relid);
  */
 ObjectAddress
 get_object_address(ObjectType objtype, List *objname, List *objargs,
-				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
+				   Relation *relp, LOCKMODE lockmode,
+				   bool missing_ok, bool missing_parent_ok)
 {
 	ObjectAddress address;
 	ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
@@ -507,7 +509,9 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 			case OBJECT_TRIGGER:
 			case OBJECT_CONSTRAINT:
 				address = get_object_address_relobject(objtype, objname,
-													   &relation, missing_ok);
+													   &relation,
+													   missing_ok,
+													   missing_parent_ok);
 				break;
 			case OBJECT_DATABASE:
 			case OBJECT_EXTENSION:
@@ -622,7 +626,7 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
 		 */
 		if (!OidIsValid(address.objectId))
 		{
-			Assert(missing_ok);
+			Assert(missing_ok || missing_parent_ok);
 			return address;
 		}
 
@@ -898,7 +902,9 @@ get_relation_by_qualified_name(ObjectType objtype, List *objname,
  */
 static ObjectAddress
 get_object_address_relobject(ObjectType objtype, List *objname,
-							 Relation *relp, bool missing_ok)
+							 Relation *relp,
+								 bool missing_ok,
+								 bool missing_parent_ok)
 {
 	ObjectAddress address;
 	Relation	relation = NULL;
@@ -942,42 +948,55 @@ 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_parent_ok);
 
-		switch (objtype)
+		if (relation != NULL)
 		{
-			case OBJECT_RULE:
-				address.classId = RewriteRelationId;
-				address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
-				address.objectSubId = 0;
-				break;
-			case OBJECT_TRIGGER:
-				address.classId = TriggerRelationId;
-				address.objectId = get_trigger_oid(reloid, depname, missing_ok);
-				address.objectSubId = 0;
-				break;
-			case OBJECT_CONSTRAINT:
-				address.classId = ConstraintRelationId;
-				address.objectId =
-					get_relation_constraint_oid(reloid, depname, missing_ok);
-				address.objectSubId = 0;
-				break;
-			default:
-				elog(ERROR, "unrecognized objtype: %d", (int) objtype);
-				/* placate compiler, which doesn't know elog won't return */
-				address.classId = InvalidOid;
-				address.objectId = InvalidOid;
-				address.objectSubId = 0;
-		}
+			reloid = RelationGetRelid(relation);
 
-		/* Avoid relcache leak when object not found. */
-		if (!OidIsValid(address.objectId))
+			switch (objtype)
+			{
+				case OBJECT_RULE:
+					address.classId = RewriteRelationId;
+					address.objectId = get_rewrite_oid(reloid, depname, missing_ok);
+					address.objectSubId = 0;
+					break;
+				case OBJECT_TRIGGER:
+					address.classId = TriggerRelationId;
+					address.objectId = get_trigger_oid(reloid, depname, missing_ok);
+					address.objectSubId = 0;
+					break;
+				case OBJECT_CONSTRAINT:
+					address.classId = ConstraintRelationId;
+					address.objectId =
+						get_relation_constraint_oid(reloid, depname, missing_ok);
+					address.objectSubId = 0;
+					break;
+				default:
+					elog(ERROR, "unrecognized objtype: %d", (int) objtype);
+					/* placate compiler, which doesn't know elog won't return */
+					address.classId = InvalidOid;
+					address.objectId = InvalidOid;
+					address.objectSubId = 0;
+			}
+
+			/* Avoid relcache leak when object not found. */
+			if (!OidIsValid(address.objectId))
+			{
+				heap_close(relation, AccessShareLock);
+				relation = NULL;	/* department of accident prevention */
+				return address;
+			}
+		}
+		else
 		{
-			heap_close(relation, AccessShareLock);
-			relation = NULL;	/* department of accident prevention */
-			return address;
+			Assert(missing_parent_ok);
+
+			address.classId = InvalidOid;
+			address.objectId = InvalidOid;
+			address.objectSubId = 0;
 		}
 	}
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index b62ec70..04e1481 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -364,7 +364,8 @@ ExecRenameStmt(RenameStmt *stmt)
 				address = get_object_address(stmt->renameType,
 											 stmt->object, stmt->objarg,
 											 &relation,
-											 AccessExclusiveLock, false);
+											 AccessExclusiveLock,
+											 false, false);
 				Assert(relation == NULL);
 
 				catalog = heap_open(address.classId, RowExclusiveLock);
@@ -431,6 +432,7 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
 											 stmt->objarg,
 											 &relation,
 											 AccessExclusiveLock,
+											 false,
 											 false);
 				Assert(relation == NULL);
 				classId = address.classId;
@@ -725,6 +727,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
 											 stmt->objarg,
 											 &relation,
 											 AccessExclusiveLock,
+											 false,
 											 false);
 				Assert(relation == NULL);
 				classId = address.classId;
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 5ecc92a..5b77e87 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -71,7 +71,8 @@ CommentObject(CommentStmt *stmt)
 	 * against concurrent DROP operations.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock, false);
+								 &relation, ShareUpdateExclusiveLock,
+								 false, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index b32ad3a..4529727 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -31,6 +31,8 @@
 
 static void does_not_exist_skipping(ObjectType objtype,
 						List *objname, List *objargs);
+static void parent_not_exists_skipping(ObjectType objtype,
+						List *objname);
 
 /*
  * Drop one or more objects.
@@ -71,12 +73,17 @@ RemoveObjects(DropStmt *stmt)
 									 objname, objargs,
 									 &relation,
 									 AccessExclusiveLock,
-									 stmt->missing_ok);
+									 stmt->missing_ok,
+									 stmt->missing_parent_ok);
 
 		/* Issue NOTICE if supplied object was not found. */
 		if (!OidIsValid(address.objectId))
 		{
-			does_not_exist_skipping(stmt->removeType, objname, objargs);
+			/* ObjectId can be invalid due missing parent relation */
+			if (stmt->missing_parent_ok && !OidIsValid(address.classId))
+				parent_not_exists_skipping(stmt->removeType, objname);
+			else
+				does_not_exist_skipping(stmt->removeType, objname, objargs);
 			continue;
 		}
 
@@ -244,3 +251,25 @@ does_not_exist_skipping(ObjectType objtype, List *objname, List *objargs)
 	else
 		ereport(NOTICE, (errmsg(msg, name, args)));
 }
+
+/*
+ * Generate a NOTICE "table does not exists, skipping". It is used when
+ * clause IF EXISTS is twice used.
+ */
+static void
+parent_not_exists_skipping(ObjectType objtype, List *objname)
+{
+	switch (objtype)
+	{
+		case OBJECT_RULE:
+		case OBJECT_TRIGGER:
+			ereport(NOTICE,
+				 (errmsg("table \%s\" does not exists, skipping",
+					NameListToString(list_truncate(list_copy(objname),
+							  list_length(objname) - 1)))));
+			break;
+		default:
+			elog(ERROR, "unexpected object type (%d)", (int) objtype);
+			break;
+	}
+}
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 798c92a..83a6d92 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2908,7 +2908,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 	 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
 	 */
 	object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								&relation, ShareUpdateExclusiveLock, false);
+								&relation, ShareUpdateExclusiveLock,
+								false, false);
 
 	/* Permission check: must own target object, too */
 	check_object_ownership(GetUserId(), stmt->objtype, object,
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
index eaf0d0d..115c395 100644
--- a/src/backend/commands/seclabel.c
+++ b/src/backend/commands/seclabel.c
@@ -88,7 +88,8 @@ ExecSecLabelStmt(SecLabelStmt *stmt)
 	 * guard against concurrent modifications.
 	 */
 	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
-								 &relation, ShareUpdateExclusiveLock, false);
+								 &relation, ShareUpdateExclusiveLock,
+								 false, false);
 
 	/* Require ownership of the target object. */
 	check_object_ownership(GetUserId(), stmt->objtype, address,
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1733da6..a8c5b85 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2798,6 +2798,7 @@ _copyDropStmt(const DropStmt *from)
 	COPY_SCALAR_FIELD(removeType);
 	COPY_SCALAR_FIELD(behavior);
 	COPY_SCALAR_FIELD(missing_ok);
+	COPY_SCALAR_FIELD(missing_parent_ok);
 	COPY_SCALAR_FIELD(concurrent);
 
 	return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 7b29812..7fe85fb 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1137,6 +1137,7 @@ _equalDropStmt(const DropStmt *a, const DropStmt *b)
 	COMPARE_SCALAR_FIELD(removeType);
 	COMPARE_SCALAR_FIELD(behavior);
 	COMPARE_SCALAR_FIELD(missing_ok);
+	COMPARE_SCALAR_FIELD(missing_parent_ok);
 	COMPARE_SCALAR_FIELD(concurrent);
 
 	return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 8dc4b1c..2fb9388 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -3546,6 +3546,7 @@ DropPLangStmt:
 					n->arguments = NIL;
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -3556,6 +3557,7 @@ DropPLangStmt:
 					n->objects = list_make1(list_make1(makeString($6)));
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -3969,6 +3971,7 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($5)));
 					n->arguments = NIL;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->behavior = $6;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -3980,6 +3983,7 @@ DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($7)));
 					n->arguments = NIL;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->behavior = $8;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -4131,6 +4135,7 @@ DropForeignServerStmt: DROP SERVER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($3)));
 					n->arguments = NIL;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->behavior = $4;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -4142,6 +4147,7 @@ DropForeignServerStmt: DROP SERVER name opt_drop_behavior
 					n->objects = list_make1(list_make1(makeString($5)));
 					n->arguments = NIL;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->behavior = $6;
 					n->concurrent = false;
 					$$ = (Node *) n;
@@ -4512,6 +4518,7 @@ DropTrigStmt:
 					n->arguments = NIL;
 					n->behavior = $6;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -4523,6 +4530,31 @@ DropTrigStmt:
 					n->arguments = NIL;
 					n->behavior = $8;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP TRIGGER name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_TRIGGER;
+					n->objects = list_make1(lappend($7, makeString($3)));
+					n->arguments = NIL;
+					n->behavior = $8;
+					n->missing_ok = false;
+					n->missing_parent_ok = true;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP TRIGGER IF_P EXISTS name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_TRIGGER;
+					n->objects = list_make1(lappend($9, makeString($5)));
+					n->arguments = NIL;
+					n->behavior = $10;
+					n->missing_ok = true;
+					n->missing_parent_ok = true;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5055,6 +5087,7 @@ DropOpClassStmt:
 					n->removeType = OBJECT_OPCLASS;
 					n->behavior = $7;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5066,6 +5099,7 @@ DropOpClassStmt:
 					n->removeType = OBJECT_OPCLASS;
 					n->behavior = $9;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5080,6 +5114,7 @@ DropOpFamilyStmt:
 					n->removeType = OBJECT_OPFAMILY;
 					n->behavior = $7;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5091,6 +5126,7 @@ DropOpFamilyStmt:
 					n->removeType = OBJECT_OPFAMILY;
 					n->behavior = $9;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -5139,6 +5175,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
 					n->missing_ok = TRUE;
+					n->missing_parent_ok = false;
 					n->objects = $5;
 					n->arguments = NIL;
 					n->behavior = $6;
@@ -5150,6 +5187,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
 					n->missing_ok = FALSE;
+					n->missing_parent_ok = false;
 					n->objects = $3;
 					n->arguments = NIL;
 					n->behavior = $4;
@@ -5161,6 +5199,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_INDEX;
 					n->missing_ok = FALSE;
+					n->missing_parent_ok = false;
 					n->objects = $4;
 					n->arguments = NIL;
 					n->behavior = $5;
@@ -5172,6 +5211,7 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_INDEX;
 					n->missing_ok = TRUE;
+					n->missing_parent_ok = false;
 					n->objects = $6;
 					n->arguments = NIL;
 					n->behavior = $7;
@@ -6635,6 +6675,7 @@ RemoveFuncStmt:
 					n->arguments = list_make1(extractArgTypes($4));
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6646,6 +6687,7 @@ RemoveFuncStmt:
 					n->arguments = list_make1(extractArgTypes($6));
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6660,6 +6702,7 @@ RemoveAggrStmt:
 					n->arguments = list_make1(extractArgTypes($4));
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6671,6 +6714,7 @@ RemoveAggrStmt:
 					n->arguments = list_make1(extractArgTypes($6));
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6685,6 +6729,7 @@ RemoveOperStmt:
 					n->arguments = list_make1($4);
 					n->behavior = $5;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6696,6 +6741,7 @@ RemoveOperStmt:
 					n->arguments = list_make1($6);
 					n->behavior = $7;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -6813,6 +6859,7 @@ DropCastStmt: DROP CAST opt_if_exists '(' Typename AS Typename ')' opt_drop_beha
 					n->arguments = list_make1(list_make1($7));
 					n->behavior = $9;
 					n->missing_ok = $3;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
@@ -7821,6 +7868,7 @@ DropRuleStmt:
 					n->arguments = NIL;
 					n->behavior = $6;
 					n->missing_ok = false;
+					n->missing_parent_ok = false;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
@@ -7832,6 +7880,31 @@ DropRuleStmt:
 					n->arguments = NIL;
 					n->behavior = $8;
 					n->missing_ok = true;
+					n->missing_parent_ok = false;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP RULE name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_RULE;
+					n->objects = list_make1(lappend($7, makeString($3)));
+					n->arguments = NIL;
+					n->behavior = $8;
+					n->missing_ok = false;
+					n->missing_parent_ok = true;
+					n->concurrent = false;
+					$$ = (Node *) n;
+				}
+			| DROP RULE IF_P EXISTS name ON IF_P EXISTS any_name opt_drop_behavior
+				{
+					DropStmt *n = makeNode(DropStmt);
+					n->removeType = OBJECT_RULE;
+					n->objects = list_make1(lappend($9, makeString($5)));
+					n->arguments = NIL;
+					n->behavior = $10;
+					n->missing_ok = true;
+					n->missing_parent_ok = true;
 					n->concurrent = false;
 					$$ = (Node *) n;
 				}
diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h
index e2a5b0d..05f20ff 100644
--- a/src/include/catalog/objectaddress.h
+++ b/src/include/catalog/objectaddress.h
@@ -30,7 +30,8 @@ typedef struct ObjectAddress
 
 extern ObjectAddress get_object_address(ObjectType objtype, List *objname,
 				   List *objargs, Relation *relp,
-				   LOCKMODE lockmode, bool missing_ok);
+				   LOCKMODE lockmode,
+				   bool missing_ok, bool missing_parent_ok);
 
 extern void check_object_ownership(Oid roleid,
 					   ObjectType objtype, ObjectAddress address,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 952fbb3..57178bd 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2003,6 +2003,7 @@ typedef struct DropStmt
 	ObjectType	removeType;		/* object type */
 	DropBehavior behavior;		/* RESTRICT or CASCADE behavior */
 	bool		missing_ok;		/* skip error if object is missing? */
+	bool		missing_parent_ok;	/* skip error if parent is missing? */
 	bool		concurrent;		/* drop index concurrently? */
 } DropStmt;
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 62fc7c5..c688999 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2630,3 +2630,10 @@ ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renam
 ERROR:  renaming an ON SELECT rule is not allowed
 DROP VIEW rule_v1;
 DROP TABLE rule_t1;
+--
+-- fault tolerant drop rule
+--
+DROP RULE IF EXISTS noexistname ON IF EXISTS noexistname;
+NOTICE:  table noexistname" does not exists, skipping
+DROP RULE noexistname ON IF EXISTS noexistname;
+NOTICE:  table noexistname" does not exists, skipping
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index 6a6ecf7..35622cc 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -1731,3 +1731,8 @@ select * from self_ref_trigger;
 drop table self_ref_trigger;
 drop function self_ref_trigger_ins_func();
 drop function self_ref_trigger_del_func();
+-- fault tolerant trigger
+drop trigger not_exists_trigger on if exists not_exists_table;
+NOTICE:  table not_exists_table" does not exists, skipping
+drop trigger if exists not_exists_trigger on if exists not_exists_table;
+NOTICE:  table not_exists_table" does not exists, skipping
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index 1e15f84..23e9423 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -1007,3 +1007,9 @@ ALTER RULE "_RETURN" ON rule_v1 RENAME TO abc; -- ON SELECT rule cannot be renam
 
 DROP VIEW rule_v1;
 DROP TABLE rule_t1;
+
+--
+-- fault tolerant drop rule
+--
+DROP RULE IF EXISTS noexistname ON IF EXISTS noexistname;
+DROP RULE noexistname ON IF EXISTS noexistname;
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 0ea2c31..6174f95 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -1173,3 +1173,7 @@ select * from self_ref_trigger;
 drop table self_ref_trigger;
 drop function self_ref_trigger_ins_func();
 drop function self_ref_trigger_del_func();
+
+-- fault tolerant trigger
+drop trigger not_exists_trigger on if exists not_exists_table;
+drop trigger if exists not_exists_trigger on if exists not_exists_table;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to