From 34e8ebae9a45ffa8f30fdee8d0b94c9589c5ca89 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Thu, 15 Sep 2016 12:00:00 -0400
Subject: [PATCH 5/7] Allow dropping multiple functions at once

The generic drop support already supported dropping multiple objects of
the same kind at once.  But the previous representation
of function signatures across two grammar symbols and structure members
made this cumbersome to do for functions, so it was not supported.  Now
that function signatures are represented by a single structure, it's
trivial to add this support.
---
 doc/src/sgml/ref/drop_aggregate.sgml            |  2 +-
 doc/src/sgml/ref/drop_function.sgml             |  2 +-
 src/backend/commands/dropcmds.c                 |  3 +++
 src/backend/parser/gram.y                       | 24 +++++++++++++++---------
 src/test/regress/expected/create_function_3.out |  6 ++----
 src/test/regress/sql/create_function_3.sql      |  2 ++
 6 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/doc/src/sgml/ref/drop_aggregate.sgml b/doc/src/sgml/ref/drop_aggregate.sgml
index c27c5ea..f239d39 100644
--- a/doc/src/sgml/ref/drop_aggregate.sgml
+++ b/doc/src/sgml/ref/drop_aggregate.sgml
@@ -21,7 +21,7 @@
 
  <refsynopsisdiv>
 <synopsis>
-DROP AGGREGATE [ IF EXISTS ] <replaceable>name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) [ CASCADE | RESTRICT ]
+DROP AGGREGATE [ IF EXISTS ] <replaceable>name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) [, ...] [ CASCADE | RESTRICT ]
 
 <phrase>where <replaceable>aggregate_signature</replaceable> is:</phrase>
 
diff --git a/doc/src/sgml/ref/drop_function.sgml b/doc/src/sgml/ref/drop_function.sgml
index 5883d13..ad76c95 100644
--- a/doc/src/sgml/ref/drop_function.sgml
+++ b/doc/src/sgml/ref/drop_function.sgml
@@ -21,7 +21,7 @@
 
  <refsynopsisdiv>
 <synopsis>
-DROP FUNCTION [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] )
+DROP FUNCTION [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) [, ...]
     [ CASCADE | RESTRICT ]
 </synopsis>
  </refsynopsisdiv>
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index ecf1428..32fe2e9 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -73,6 +73,9 @@ RemoveObjects(DropStmt *stmt)
 			objargs = lfirst(cell2);
 		}
 
+		if (stmt->removeType == OBJECT_AGGREGATE || stmt->removeType == OBJECT_FUNCTION)
+			objname = list_make1(objname);
+
 		/* Get an ObjectAddress for the object. */
 		address = get_object_address(stmt->removeType,
 									 objname, objargs,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 27110a5..215e686 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -339,7 +339,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <list>	privileges privilege_list
 %type <privtarget> privilege_target
 %type <funwithargs> function_with_argtypes aggregate_with_argtypes
-%type <list>	function_with_argtypes_list
+%type <list>	function_with_argtypes_list aggregate_with_argtypes_list
 %type <ival>	defacl_privilege_target
 %type <defelt>	DefACLOption
 %type <list>	DefACLOptionList
@@ -7063,6 +7063,12 @@ aggregate_with_argtypes:
 				}
 		;
 
+aggregate_with_argtypes_list:
+			aggregate_with_argtypes					{ $$ = list_make1($1); }
+			| aggregate_with_argtypes_list ',' aggregate_with_argtypes
+													{ $$ = lappend($1, $3); }
+		;
+
 createfunc_opt_list:
 			/* Must be at least one to prevent conflict */
 			createfunc_opt_item						{ $$ = list_make1($1); }
@@ -7244,22 +7250,22 @@ opt_restrict:
  *****************************************************************************/
 
 RemoveFuncStmt:
-			DROP FUNCTION function_with_argtypes opt_drop_behavior
+			DROP FUNCTION function_with_argtypes_list opt_drop_behavior
 				{
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_FUNCTION;
-					n->objects = list_make1(list_make1($3));
+					n->objects = $3;
 					n->arguments = NIL;
 					n->behavior = $4;
 					n->missing_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
-			| DROP FUNCTION IF_P EXISTS function_with_argtypes opt_drop_behavior
+			| DROP FUNCTION IF_P EXISTS function_with_argtypes_list opt_drop_behavior
 				{
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_FUNCTION;
-					n->objects = list_make1(list_make1($5));
+					n->objects = $5;
 					n->arguments = NIL;
 					n->behavior = $6;
 					n->missing_ok = true;
@@ -7269,22 +7275,22 @@ RemoveFuncStmt:
 		;
 
 RemoveAggrStmt:
-			DROP AGGREGATE aggregate_with_argtypes opt_drop_behavior
+			DROP AGGREGATE aggregate_with_argtypes_list opt_drop_behavior
 				{
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_AGGREGATE;
-					n->objects = list_make1(list_make1($3));
+					n->objects = $3;
 					n->arguments = NIL;
 					n->behavior = $4;
 					n->missing_ok = false;
 					n->concurrent = false;
 					$$ = (Node *)n;
 				}
-			| DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes opt_drop_behavior
+			| DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes_list opt_drop_behavior
 				{
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = OBJECT_AGGREGATE;
-					n->objects = list_make1(list_make1($5));
+					n->objects = $5;
 					n->arguments = NIL;
 					n->behavior = $6;
 					n->missing_ok = true;
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index 7bb957b..cc4e98a 100644
--- a/src/test/regress/expected/create_function_3.out
+++ b/src/test/regress/expected/create_function_3.out
@@ -217,9 +217,10 @@ SELECT routine_name, ordinal_position, parameter_name, parameter_default
  functest_is_3 |                2 | b              | 
 (7 rows)
 
+DROP FUNCTION functest_IS_1(int, int, text), functest_IS_2(int), functest_IS_3(int);
 -- Cleanups
 DROP SCHEMA temp_func_test CASCADE;
-NOTICE:  drop cascades to 19 other objects
+NOTICE:  drop cascades to 16 other objects
 DETAIL:  drop cascades to function functest_a_1(text,date)
 drop cascades to function functest_a_2(text[])
 drop cascades to function functest_a_3()
@@ -236,8 +237,5 @@ drop cascades to function functext_f_1(integer)
 drop cascades to function functext_f_2(integer)
 drop cascades to function functext_f_3(integer)
 drop cascades to function functext_f_4(integer)
-drop cascades to function functest_is_1(integer,integer,text)
-drop cascades to function functest_is_2(integer)
-drop cascades to function functest_is_3(integer)
 DROP USER regress_unpriv_user;
 RESET search_path;
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index 43454ef..66a463b 100644
--- a/src/test/regress/sql/create_function_3.sql
+++ b/src/test/regress/sql/create_function_3.sql
@@ -156,6 +156,8 @@ CREATE FUNCTION functest_IS_3(a int default 1, out b int)
     WHERE routine_schema = 'temp_func_test' AND routine_name ~ '^functest_is_'
     ORDER BY 1, 2;
 
+DROP FUNCTION functest_IS_1(int, int, text), functest_IS_2(int), functest_IS_3(int);
+
 
 -- Cleanups
 DROP SCHEMA temp_func_test CASCADE;
-- 
2.10.2

