From e7838b60dbf0a8cd7f35591db2f9aab78d8903cb Mon Sep 17 00:00:00 2001
From: Nicolas Williams <nico@cryptonector.com>
Date: Wed, 11 Jul 2018 19:53:01 -0500
Subject: [PATCH] Add ALWAYS DEFERRED option for CONSTRAINTs (CR)

---
 doc/src/sgml/catalogs.sgml                 |  2 +-
 doc/src/sgml/ref/set_constraints.sgml      | 10 ++++++----
 src/backend/catalog/index.c                |  1 -
 src/backend/catalog/information_schema.sql |  8 +++-----
 src/backend/commands/trigger.c             |  1 -
 src/backend/parser/gram.y                  | 18 ++++++++++--------
 6 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 291e6a9..4d42594 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -2245,7 +2245,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
       <entry>Constraint deferral option:
             <literal>a</literal> = always deferred,
             <literal>d</literal> = deferrable,
-            <literal>d</literal> = deferrable initially deferred,
+            <literal>i</literal> = deferrable initially deferred,
             <literal>n</literal> = not deferrable
           </entry>
      </row>
diff --git a/doc/src/sgml/ref/set_constraints.sgml b/doc/src/sgml/ref/set_constraints.sgml
index 671332a..390015e 100644
--- a/doc/src/sgml/ref/set_constraints.sgml
+++ b/doc/src/sgml/ref/set_constraints.sgml
@@ -34,11 +34,13 @@ SET CONSTRAINTS { ALL | <replaceable class="parameter">name</replaceable> [, ...
   </para>
 
   <para>
-   Upon creation, a constraint is given one of three
+   Upon creation, a constraint is given one of four
    characteristics: <literal>DEFERRABLE INITIALLY DEFERRED</literal>,
-   <literal>DEFERRABLE INITIALLY IMMEDIATE</literal>, or
-   <literal>NOT DEFERRABLE</literal>. The third
-   class is always <literal>IMMEDIATE</literal> and is not affected by the
+   <literal>DEFERRABLE INITIALLY IMMEDIATE</literal>,
+   <literal>NOT DEFERRABLE</literal>, or <literal>ALWAYS DEFERRED</literal>.
+   The third
+   class is always <literal>IMMEDIATE</literal>, while the fourth class is
+   always <literal>DEFERRED</literal>, and neither affected by the
    <command>SET CONSTRAINTS</command> command.  The first two classes start
    every transaction in the indicated mode, but their behavior can be changed
    within a transaction by <command>SET CONSTRAINTS</command>.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 795a7a9..45b52b4 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1070,7 +1070,6 @@ index_create(Relation heapRelation,
 
 				recordDependencyOn(&myself, &referenced, deptype);
 			}
-			Assert((flags & INDEX_CREATE_ADD_CONSTRAINT) == 0);
 		}
 
 		/* Store dependency on parent index, if any */
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index bde6199..dd4792a 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -894,11 +894,9 @@ CREATE VIEW domain_constraints AS
            CAST(CASE WHEN condeferral = 'n' THEN 'NO' ELSE 'YES' END
              AS yes_or_no) AS is_deferrable,
            CAST(CASE WHEN condeferral = 'i' OR condeferral = 'a' THEN 'YES' ELSE 'NO' END
-             AS yes_or_no) AS initially_deferred
-	   /*
-	    * XXX Can we add is_always_deferred here?  Are there
-	    * standards considerations?
-	    */
+             AS yes_or_no) AS initially_deferred,
+           CAST(CASE WHEN condeferral = 'a' THEN 'YES' ELSE 'NO' END
+             AS yes_or_no) AS always_deferred
     FROM pg_namespace rs, pg_namespace n, pg_constraint con, pg_type t
     WHERE rs.oid = con.connamespace
           AND n.oid = t.typnamespace
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 41dc6a4..33b1095 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -3627,7 +3627,6 @@ typedef struct AfterTriggerSharedData
 	TriggerEvent ats_event;		/* event type indicator, see trigger.h */
 	Oid			ats_tgoid;		/* the trigger's ID */
 	Oid			ats_relid;		/* the relation it's on */
-	bool			ats_alwaysdeferred;	/* whether this can be deferred */
 	CommandId	ats_firing_id;	/* ID for firing cycle */
 	struct AfterTriggersTableData *ats_table;	/* transition table access */
 } AfterTriggerSharedData;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index dab721a..9aaa2af 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -185,8 +185,8 @@ static void SplitColQualList(List *qualList,
 							 List **constraintList, CollateClause **collClause,
 							 core_yyscan_t yyscanner);
 static void processCASbits(int cas_bits, int location, const char *constrType,
-			   char *deferral,
-			   bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner);
+			   char *deferral, bool *not_valid, bool *no_inherit,
+			   core_yyscan_t yyscanner);
 static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %}
@@ -5579,13 +5579,13 @@ ConstraintAttributeSpec:
 						(newspec & (CAS_INITIALLY_IMMEDIATE)))
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
-								 errmsg("conflicting constraint properties 1"),
+								 errmsg("conflicting constraint properties"),
 								 parser_errposition(@2)));
 					if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) ||
 						(newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED))
 						ereport(ERROR,
 								(errcode(ERRCODE_SYNTAX_ERROR),
-								 errmsg("conflicting constraint properties 2"),
+								 errmsg("conflicting constraint properties"),
 								 parser_errposition(@2)));
 					$$ = newspec;
 				}
@@ -16234,8 +16234,8 @@ SplitColQualList(List *qualList,
  */
 static void
 processCASbits(int cas_bits, int location, const char *constrType,
-			   char *deferral,
-			   bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner)
+			   char *deferral, bool *not_valid, bool *no_inherit,
+			   core_yyscan_t yyscanner)
 {
 	/* defaults */
 	if (deferral)
@@ -16254,7 +16254,8 @@ processCASbits(int cas_bits, int location, const char *constrType,
 					 errmsg("%s constraints cannot be marked ALWAYS DEFERRED",
 							constrType),
 					 parser_errposition(location)));
-	} else if (cas_bits & CAS_INITIALLY_DEFERRED)
+	}
+	else if (cas_bits & CAS_INITIALLY_DEFERRED)
 	{
 		if (deferral)
 			*deferral = 'i';
@@ -16265,7 +16266,8 @@ processCASbits(int cas_bits, int location, const char *constrType,
 					 errmsg("%s constraints cannot be marked INITIALLY DEFERRED",
 							constrType),
 					 parser_errposition(location)));
-	} else if (cas_bits & CAS_DEFERRABLE)
+	}
+	else if (cas_bits & CAS_DEFERRABLE)
 	{
 		if (deferral)
 			*deferral = 'd';
-- 
2.7.4

