>From d53070c5b5192457b383757733de4756355d65b2 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Fri, 9 May 2014 18:32:23 -0400
Subject: [PATCH 02/26] deparse/core: event triggers support GRANT/REVOKE

---
 doc/src/sgml/event-trigger.sgml      | 15 ++++++++++++++-
 src/backend/commands/event_trigger.c | 30 ++++++++++++++++++++++++++++++
 src/backend/tcop/utility.c           | 21 ++++++++++++++++-----
 src/include/commands/event_trigger.h |  1 +
 4 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/event-trigger.sgml b/doc/src/sgml/event-trigger.sgml
index 6f71a27..49b8384 100644
--- a/doc/src/sgml/event-trigger.sgml
+++ b/doc/src/sgml/event-trigger.sgml
@@ -36,7 +36,8 @@
 
    <para>
      The <literal>ddl_command_start</> event occurs just before the
-     execution of a <literal>CREATE</>, <literal>ALTER</>, or <literal>DROP</>
+     execution of a <literal>CREATE</>, <literal>ALTER</>, <literal>DROP</>,
+     <literal>GRANT</> or <literal>REVOKE</>
      command.  No check whether the affected object exists or doesn't exist is
      performed before the event trigger fires.
      As an exception, however, this event does not occur for
@@ -622,12 +623,24 @@
         <entry align="center"><literal>X</literal></entry>
        </row>
        <row>
+        <entry align="left"><literal>GRANT</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>-</literal></entry>
+       </row>
+       <row>
         <entry align="left"><literal>IMPORT FOREIGN SCHEMA</literal></entry>
         <entry align="center"><literal>X</literal></entry>
         <entry align="center"><literal>X</literal></entry>
         <entry align="center"><literal>-</literal></entry>
        </row>
        <row>
+        <entry align="left"><literal>REVOKE</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>X</literal></entry>
+        <entry align="center"><literal>-</literal></entry>
+       </row>
+       <row>
         <entry align="left"><literal>SELECT INTO</literal></entry>
         <entry align="center"><literal>X</literal></entry>
         <entry align="center"><literal>X</literal></entry>
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 1b8c94b..6abd9fa 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -251,6 +251,8 @@ check_ddl_tag(const char *tag)
 		pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
 		pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
 		pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||
+		pg_strcasecmp(tag, "GRANT") == 0 ||
+		pg_strcasecmp(tag, "REVOKE") == 0 ||
 		pg_strcasecmp(tag, "DROP OWNED") == 0 ||
 		pg_strcasecmp(tag, "IMPORT FOREIGN SCHEMA") == 0)
 		return EVENT_TRIGGER_COMMAND_TAG_OK;
@@ -1013,6 +1015,34 @@ EventTriggerSupportsObjectClass(ObjectClass objclass)
 	return true;
 }
 
+bool
+EventTriggerSupportsGrantObjectType(GrantObjectType objtype)
+{
+	switch (objtype)
+	{
+		case ACL_OBJECT_DATABASE:
+		case ACL_OBJECT_TABLESPACE:
+			/* no support for global objects */
+			return false;
+
+		case ACL_OBJECT_COLUMN:
+		case ACL_OBJECT_RELATION:
+		case ACL_OBJECT_SEQUENCE:
+		case ACL_OBJECT_DOMAIN:
+		case ACL_OBJECT_FDW:
+		case ACL_OBJECT_FOREIGN_SERVER:
+		case ACL_OBJECT_FUNCTION:
+		case ACL_OBJECT_LANGUAGE:
+		case ACL_OBJECT_LARGEOBJECT:
+		case ACL_OBJECT_NAMESPACE:
+		case ACL_OBJECT_TYPE:
+			return true;
+		default:
+			Assert(false);
+			return true;
+	}
+}
+
 /*
  * Prepare event trigger state for a new complete query to run, if necessary;
  * returns whether this was done.  If it was, EventTriggerEndCompleteQuery must
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index ab223ad..559a3d3 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -547,11 +547,6 @@ standard_ProcessUtility(Node *parsetree,
 			DeallocateQuery((DeallocateStmt *) parsetree);
 			break;
 
-		case T_GrantStmt:
-			/* no event triggers for global objects */
-			ExecuteGrantStmt((GrantStmt *) parsetree);
-			break;
-
 		case T_GrantRoleStmt:
 			/* no event triggers for global objects */
 			GrantRole((GrantRoleStmt *) parsetree);
@@ -781,6 +776,18 @@ standard_ProcessUtility(Node *parsetree,
 			 * in some cases, so we "fast path" them in the other cases.
 			 */
 
+		case T_GrantStmt:
+			{
+				GrantStmt  *stmt = (GrantStmt *) parsetree;
+
+				if (EventTriggerSupportsGrantObjectType(stmt->objtype))
+					ProcessUtilitySlow(parsetree, queryString,
+									   context, params,
+									   dest, completionTag);
+				else
+					ExecuteGrantStmt((GrantStmt *) parsetree);
+			}
+
 		case T_DropStmt:
 			{
 				DropStmt   *stmt = (DropStmt *) parsetree;
@@ -1313,6 +1320,10 @@ ProcessUtilitySlow(Node *parsetree,
 				ExecAlterOwnerStmt((AlterOwnerStmt *) parsetree);
 				break;
 
+			case T_GrantStmt:
+				ExecuteGrantStmt((GrantStmt *) parsetree);
+				break;
+
 			case T_DropOwnedStmt:
 				DropOwnedObjects((DropOwnedStmt *) parsetree);
 				break;
diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h
index 0233f4c..1348997 100644
--- a/src/include/commands/event_trigger.h
+++ b/src/include/commands/event_trigger.h
@@ -43,6 +43,7 @@ extern void AlterEventTriggerOwner_oid(Oid, Oid newOwnerId);
 
 extern bool EventTriggerSupportsObjectType(ObjectType obtype);
 extern bool EventTriggerSupportsObjectClass(ObjectClass objclass);
+extern bool EventTriggerSupportsGrantObjectType(GrantObjectType objtype);
 extern void EventTriggerDDLCommandStart(Node *parsetree);
 extern void EventTriggerDDLCommandEnd(Node *parsetree);
 extern void EventTriggerSQLDrop(Node *parsetree);
-- 
1.9.1

