OSDN Git Service

Rework parsing of ConstraintAttributeSpec to improve NOT VALID handling.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 15 Jun 2011 23:05:11 +0000 (19:05 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 15 Jun 2011 23:06:21 +0000 (19:06 -0400)
The initial commit of the ALTER TABLE ADD FOREIGN KEY NOT VALID feature
failed to support labeling such constraints as deferrable.  The best fix
for this seems to be to fold NOT VALID into ConstraintAttributeSpec.
That's a bit more general than the documented syntax, but it allows
better-targeted syntax error messages.

In addition, do some mostly-but-not-entirely-cosmetic code review for
the whole NOT VALID patch.

doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/alter_table.sgml
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/parser/gram.y
src/backend/parser/parse_utilcmd.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/parsenodes.h
src/interfaces/ecpg/preproc/ecpg.addons

index 8504555..24d7d98 100644 (file)
       <entry><structfield>convalidated</structfield></entry>
       <entry><type>bool</type></entry>
       <entry></entry>
-      <entry>Has the constraint been validated? Can only be false for foreign keys</entry>
+      <entry>Has the constraint been validated?
+       Currently, can only be false for foreign keys</entry>
      </row>
 
      <row>
index 4e02438..01d3105 100644 (file)
@@ -42,9 +42,8 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET ( <replaceable class="PARAMETER">attribute_option</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] )
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> RESET ( <replaceable class="PARAMETER">attribute_option</replaceable> [, ... ] )
     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
-    ADD <replaceable class="PARAMETER">table_constraint</replaceable>
-    ADD <replaceable class="PARAMETER">table_constraint_using_index</replaceable>
     ADD <replaceable class="PARAMETER">table_constraint</replaceable> [ NOT VALID ]
+    ADD <replaceable class="PARAMETER">table_constraint_using_index</replaceable>
     VALIDATE CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable>
     DROP CONSTRAINT [ IF EXISTS ]  <replaceable class="PARAMETER">constraint_name</replaceable> [ RESTRICT | CASCADE ]
     DISABLE TRIGGER [ <replaceable class="PARAMETER">trigger_name</replaceable> | ALL | USER ]
@@ -235,27 +234,21 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
    </varlistentry>
 
    <varlistentry>
-    <term><literal>ADD <replaceable class="PARAMETER">table_constraint</replaceable>
-          [ NOT VALID ]</literal></term>
+    <term><literal>ADD <replaceable class="PARAMETER">table_constraint</replaceable> [ NOT VALID ]</literal></term>
     <listitem>
      <para>
       This form adds a new constraint to a table using the same syntax as
-      <xref linkend="SQL-CREATETABLE">. Newly added foreign key constraints can
-      also be defined as <literal>NOT VALID</literal> to avoid the
-      potentially lengthy initial check that must otherwise be performed.
-      Constraint checks are skipped at create table time, so
-      <xref linkend="SQL-CREATETABLE"> does not contain this option.
-     </para>
-    </listitem>
-   </varlistentry>
-
-   <varlistentry>
-    <term><literal>VALIDATE CONSTRAINT</literal></term>
-    <listitem>
-     <para>
-      This form validates a foreign key constraint that was previously created
-      as <literal>NOT VALID</literal>. Constraints already marked valid do not
-      cause an error response.
+      <xref linkend="SQL-CREATETABLE">, plus the option <literal>NOT
+      VALID</literal>, which is currently only allowed for foreign key
+      constraints.
+      If the constraint is marked <literal>NOT VALID</literal>, the
+      potentially-lengthy initial check to verify that all rows in the table
+      satisfy the constraint is skipped.  The constraint will still be
+      enforced against subsequent inserts or updates (that is, they'll fail
+      unless there is a matching row in the referenced table).  But the
+      database will not assume that the constraint holds for all rows in
+      the table, until it is validated by using the <literal>VALIDATE
+      CONSTRAINT</literal> option.
      </para>
     </listitem>
    </varlistentry>
@@ -312,6 +305,21 @@ ALTER TABLE <replaceable class="PARAMETER">name</replaceable>
    </varlistentry>
 
    <varlistentry>
+    <term><literal>VALIDATE CONSTRAINT</literal></term>
+    <listitem>
+     <para>
+      This form validates a foreign key constraint that was previously created
+      as <literal>NOT VALID</literal>, by scanning the table to ensure there
+      are no unmatched rows.  Nothing happens if the constraint is
+      already marked valid.
+      The value of separating validation from initial creation of the
+      constraint is that validation requires a lesser lock on the table
+      than constraint creation does.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>DROP CONSTRAINT [ IF EXISTS ]</literal></term>
     <listitem>
      <para>
index 2c9f855..912f45c 100644 (file)
@@ -258,7 +258,7 @@ static void AlterIndexNamespaces(Relation classRel, Relation rel,
 static void AlterSeqNamespaces(Relation classRel, Relation rel,
                                   Oid oldNspOid, Oid newNspOid,
                                   const char *newNspName, LOCKMODE lockmode);
-static void ATExecValidateConstraint(Relation rel, const char *constrName);
+static void ATExecValidateConstraint(Relation rel, char *constrName);
 static int transformColumnNameList(Oid relId, List *colList,
                                                int16 *attnums, Oid *atttypids);
 static int transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid,
@@ -5726,9 +5726,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
        createForeignKeyTriggers(rel, fkconstraint, constrOid, indexOid);
 
        /*
-        * Tell Phase 3 to check that the constraint is satisfied by existing rows
-        * We can skip this during table creation or if requested explicitly by
-        * specifying NOT VALID on an alter table statement.
+        * Tell Phase 3 to check that the constraint is satisfied by existing rows.
+        * We can skip this during table creation, or if requested explicitly by
+        * specifying NOT VALID in an ADD FOREIGN KEY command.
         */
        if (!fkconstraint->skip_validation)
        {
@@ -5755,7 +5755,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
  * ALTER TABLE VALIDATE CONSTRAINT
  */
 static void
-ATExecValidateConstraint(Relation rel, const char *constrName)
+ATExecValidateConstraint(Relation rel, char *constrName)
 {
        Relation        conrel;
        SysScanDesc scan;
@@ -5810,7 +5810,7 @@ ATExecValidateConstraint(Relation rel, const char *constrName)
                 */
                refrel = heap_open(con->confrelid, RowShareLock);
 
-               validateForeignKeyConstraint((char *) constrName, rel, refrel,
+               validateForeignKeyConstraint(constrName, rel, refrel,
                                                                         con->conindid,
                                                                         conid);
 
@@ -5830,6 +5830,7 @@ ATExecValidateConstraint(Relation rel, const char *constrName)
        heap_close(conrel, RowExclusiveLock);
 }
 
+
 /*
  * transformColumnNameList - transform list of column names
  *
index ce36ea8..798d8a8 100644 (file)
@@ -1006,6 +1006,8 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
                }
                fkcon->deferrable = stmt->deferrable;
                fkcon->initdeferred = stmt->initdeferred;
+               fkcon->skip_validation = false;
+               fkcon->initially_valid = true;
 
                /* ... and execute it */
                ProcessUtility((Node *) atstmt,
index 1d39674..62cff8a 100644 (file)
@@ -94,6 +94,13 @@ typedef struct PrivTarget
        List       *objs;
 } PrivTarget;
 
+/* ConstraintAttributeSpec yields an integer bitmask of these flags: */
+#define CAS_NOT_DEFERRABLE                     0x01
+#define CAS_DEFERRABLE                         0x02
+#define CAS_INITIALLY_IMMEDIATE                0x04
+#define CAS_INITIALLY_DEFERRED         0x08
+#define CAS_NOT_VALID                          0x10
+
 
 #define parser_yyerror(msg)  scanner_yyerror(msg, yyscanner)
 #define parser_errposition(pos)  scanner_errposition(pos, yyscanner)
@@ -135,6 +142,9 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
 static void SplitColQualList(List *qualList,
                                                         List **constraintList, CollateClause **collClause,
                                                         core_yyscan_t yyscanner);
+static void processCASbits(int cas_bits, int location, const char *constrType,
+                          bool *deferrable, bool *initdeferred, bool *not_valid,
+                          core_yyscan_t yyscanner);
 
 %}
 
@@ -429,8 +439,7 @@ static void SplitColQualList(List *qualList,
 %type <list>   ColQualList
 %type <node>   ColConstraint ColConstraintElem ConstraintAttr
 %type <ival>   key_actions key_delete key_match key_update key_action
-%type <ival>   ConstraintAttributeSpec ConstraintDeferrabilitySpec
-                               ConstraintTimeSpec
+%type <ival>   ConstraintAttributeSpec ConstraintAttributeElem
 %type <str>            ExistingIndex
 
 %type <list>   constraints_set_list
@@ -2638,7 +2647,7 @@ ColConstraintElem:
                                        n->fk_matchtype         = $4;
                                        n->fk_upd_action        = (char) ($5 >> 8);
                                        n->fk_del_action        = (char) ($5 & 0xFF);
-                                       n->skip_validation  = FALSE;
+                                       n->skip_validation  = false;
                                        n->initially_valid  = true;
                                        $$ = (Node *)n;
                                }
@@ -2654,7 +2663,10 @@ ColConstraintElem:
  * combinations.
  *
  * See also ConstraintAttributeSpec, which can be used in places where
- * there is no parsing conflict.
+ * there is no parsing conflict.  (Note: currently, NOT VALID is an allowed
+ * clause in ConstraintAttributeSpec, but not here.  Someday we might need
+ * to allow it here too, but for the moment it doesn't seem useful in the
+ * statements that use ConstraintAttr.)
  */
 ConstraintAttr:
                        DEFERRABLE
@@ -2746,11 +2758,9 @@ ConstraintElem:
                                        n->location = @1;
                                        n->raw_expr = $3;
                                        n->cooked_expr = NULL;
-                                       if ($5 != 0)
-                                               ereport(ERROR,
-                                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                                                errmsg("CHECK constraints cannot be deferred"),
-                                                                parser_errposition(@5)));
+                                       processCASbits($5, @5, "CHECK",
+                                                                  NULL, NULL, NULL,
+                                                                  yyscanner);
                                        $$ = (Node *)n;
                                }
                        | UNIQUE '(' columnList ')' opt_definition OptConsTableSpace
@@ -2763,8 +2773,9 @@ ConstraintElem:
                                        n->options = $5;
                                        n->indexname = NULL;
                                        n->indexspace = $6;
-                                       n->deferrable = ($7 & 1) != 0;
-                                       n->initdeferred = ($7 & 2) != 0;
+                                       processCASbits($7, @7, "UNIQUE",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
                                        $$ = (Node *)n;
                                }
                        | UNIQUE ExistingIndex ConstraintAttributeSpec
@@ -2776,8 +2787,9 @@ ConstraintElem:
                                        n->options = NIL;
                                        n->indexname = $2;
                                        n->indexspace = NULL;
-                                       n->deferrable = ($3 & 1) != 0;
-                                       n->initdeferred = ($3 & 2) != 0;
+                                       processCASbits($3, @3, "UNIQUE",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
                                        $$ = (Node *)n;
                                }
                        | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
@@ -2790,8 +2802,9 @@ ConstraintElem:
                                        n->options = $6;
                                        n->indexname = NULL;
                                        n->indexspace = $7;
-                                       n->deferrable = ($8 & 1) != 0;
-                                       n->initdeferred = ($8 & 2) != 0;
+                                       processCASbits($8, @8, "PRIMARY KEY",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
                                        $$ = (Node *)n;
                                }
                        | PRIMARY KEY ExistingIndex ConstraintAttributeSpec
@@ -2803,8 +2816,9 @@ ConstraintElem:
                                        n->options = NIL;
                                        n->indexname = $3;
                                        n->indexspace = NULL;
-                                       n->deferrable = ($4 & 1) != 0;
-                                       n->initdeferred = ($4 & 2) != 0;
+                                       processCASbits($4, @4, "PRIMARY KEY",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
                                        $$ = (Node *)n;
                                }
                        | EXCLUDE access_method_clause '(' ExclusionConstraintList ')'
@@ -2820,8 +2834,9 @@ ConstraintElem:
                                        n->indexname            = NULL;
                                        n->indexspace           = $7;
                                        n->where_clause         = $8;
-                                       n->deferrable           = ($9 & 1) != 0;
-                                       n->initdeferred         = ($9 & 2) != 0;
+                                       processCASbits($9, @9, "EXCLUDE",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
                                        $$ = (Node *)n;
                                }
                        | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
@@ -2836,27 +2851,11 @@ ConstraintElem:
                                        n->fk_matchtype         = $9;
                                        n->fk_upd_action        = (char) ($10 >> 8);
                                        n->fk_del_action        = (char) ($10 & 0xFF);
-                                       n->deferrable           = ($11 & 1) != 0;
-                                       n->initdeferred         = ($11 & 2) != 0;
-                                       n->skip_validation  = false;
-                                       n->initially_valid  = true;
-                                       $$ = (Node *)n;
-                               }
-                       | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
-                               opt_column_list key_match key_actions
-                               NOT VALID
-                               {
-                                       Constraint *n = makeNode(Constraint);
-                                       n->contype = CONSTR_FOREIGN;
-                                       n->location = @1;
-                                       n->pktable                      = $7;
-                                       n->fk_attrs                     = $4;
-                                       n->pk_attrs                     = $8;
-                                       n->fk_matchtype         = $9;
-                                       n->fk_upd_action        = (char) ($10 >> 8);
-                                       n->fk_del_action        = (char) ($10 & 0xFF);
-                                       n->skip_validation  = true;
-                                       n->initially_valid  = false;
+                                       processCASbits($11, @11, "FOREIGN KEY",
+                                                                  &n->deferrable, &n->initdeferred,
+                                                                  &n->skip_validation,
+                                                                  yyscanner);
+                                       n->initially_valid = !n->skip_validation;
                                        $$ = (Node *)n;
                                }
                ;
@@ -4031,8 +4030,9 @@ CreateTrigStmt:
                                        n->columns = (List *) lsecond($6);
                                        n->whenClause = $14;
                                        n->isconstraint  = TRUE;
-                                       n->deferrable = ($10 & 1) != 0;
-                                       n->initdeferred = ($10 & 2) != 0;
+                                       processCASbits($10, @10, "TRIGGER",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
                                        n->constrrel = $9;
                                        $$ = (Node *)n;
                                }
@@ -4135,45 +4135,40 @@ OptConstrFromTable:
                ;
 
 ConstraintAttributeSpec:
-                       ConstraintDeferrabilitySpec
-                               { $$ = $1; }
-                       | ConstraintDeferrabilitySpec ConstraintTimeSpec
+                       /*EMPTY*/
+                               { $$ = 0; }
+                       | ConstraintAttributeSpec ConstraintAttributeElem
                                {
-                                       if ($1 == 0 && $2 != 0)
+                                       /*
+                                        * We must complain about conflicting options.
+                                        * We could, but choose not to, complain about redundant
+                                        * options (ie, where $2's bit is already set in $1).
+                                        */
+                                       int             newspec = $1 | $2;
+
+                                       /* special message for this case */
+                                       if ((newspec & (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED)) == (CAS_NOT_DEFERRABLE | CAS_INITIALLY_DEFERRED))
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                                                 errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
-                                                                parser_errposition(@1)));
-                                       $$ = $1 | $2;
-                               }
-                       | ConstraintTimeSpec
-                               {
-                                       if ($1 != 0)
-                                               $$ = 3;
-                                       else
-                                               $$ = 0;
-                               }
-                       | ConstraintTimeSpec ConstraintDeferrabilitySpec
-                               {
-                                       if ($2 == 0 && $1 != 0)
+                                                                parser_errposition(@2)));
+                                       /* generic message for other conflicts */
+                                       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("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
-                                                                parser_errposition(@1)));
-                                       $$ = $1 | $2;
+                                                                errmsg("conflicting constraint properties"),
+                                                                parser_errposition(@2)));
+                                       $$ = newspec;
                                }
-                       | /*EMPTY*/
-                               { $$ = 0; }
                ;
 
-ConstraintDeferrabilitySpec:
-                       NOT DEFERRABLE                                                  { $$ = 0; }
-                       | DEFERRABLE                                                    { $$ = 1; }
-               ;
-
-ConstraintTimeSpec:
-                       INITIALLY IMMEDIATE                                             { $$ = 0; }
-                       | INITIALLY DEFERRED                                    { $$ = 2; }
+ConstraintAttributeElem:
+                       NOT DEFERRABLE                                  { $$ = CAS_NOT_DEFERRABLE; }
+                       | DEFERRABLE                                    { $$ = CAS_DEFERRABLE; }
+                       | INITIALLY IMMEDIATE                   { $$ = CAS_INITIALLY_IMMEDIATE; }
+                       | INITIALLY DEFERRED                    { $$ = CAS_INITIALLY_DEFERRED; }
+                       | NOT VALID                                             { $$ = CAS_NOT_VALID; }
                ;
 
 
@@ -4217,8 +4212,9 @@ CreateAssertStmt:
                                        n->trigname = $3;
                                        n->args = list_make1($6);
                                        n->isconstraint  = TRUE;
-                                       n->deferrable = ($8 & 1) != 0;
-                                       n->initdeferred = ($8 & 2) != 0;
+                                       processCASbits($8, @8, "ASSERTION",
+                                                                  &n->deferrable, &n->initdeferred, NULL,
+                                                                  yyscanner);
 
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -12865,6 +12861,64 @@ SplitColQualList(List *qualList,
        *constraintList = qualList;
 }
 
+/*
+ * Process result of ConstraintAttributeSpec, and set appropriate bool flags
+ * in the output command node.  Pass NULL for any flags the particular
+ * command doesn't support.
+ */
+static void
+processCASbits(int cas_bits, int location, const char *constrType,
+                          bool *deferrable, bool *initdeferred, bool *not_valid,
+                          core_yyscan_t yyscanner)
+{
+       /* defaults */
+       if (deferrable)
+               *deferrable = false;
+       if (initdeferred)
+               *initdeferred = false;
+       if (not_valid)
+               *not_valid = false;
+
+       if (cas_bits & (CAS_DEFERRABLE | CAS_INITIALLY_DEFERRED))
+       {
+               if (deferrable)
+                       *deferrable = true;
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        /* translator: %s is CHECK, UNIQUE, or similar */
+                                        errmsg("%s constraints cannot be marked DEFERRABLE",
+                                                       constrType),
+                                        parser_errposition(location)));
+       }
+
+       if (cas_bits & CAS_INITIALLY_DEFERRED)
+       {
+               if (initdeferred)
+                       *initdeferred = true;
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        /* translator: %s is CHECK, UNIQUE, or similar */
+                                        errmsg("%s constraints cannot be marked DEFERRABLE",
+                                                       constrType),
+                                        parser_errposition(location)));
+       }
+
+       if (cas_bits & CAS_NOT_VALID)
+       {
+               if (not_valid)
+                       *not_valid = true;
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        /* translator: %s is CHECK, UNIQUE, or similar */
+                                        errmsg("%s constraints cannot be marked NOT VALID",
+                                                       constrType),
+                                        parser_errposition(location)));
+       }
+}
+
 /* parser_init()
  * Initialize to parse one query string
  */
index 485bf4b..51899c6 100644 (file)
@@ -1751,7 +1751,8 @@ transformFKConstraints(CreateStmtContext *cxt,
 
        /*
         * If CREATE TABLE or adding a column with NULL default, we can safely
-        * skip validation of the constraint.
+        * skip validation of FK constraints, and nonetheless mark them valid.
+        * (This will override any user-supplied NOT VALID flag.)
         */
        if (skipValidation)
        {
index 06cf6fa..00920f9 100644 (file)
@@ -1372,7 +1372,6 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
                appendStringInfo(&buf, " DEFERRABLE");
        if (conForm->condeferred)
                appendStringInfo(&buf, " INITIALLY DEFERRED");
-
        if (!conForm->convalidated)
                appendStringInfoString(&buf, " NOT VALID");
 
index 14937d4..c65e3cd 100644 (file)
@@ -1221,7 +1221,7 @@ typedef enum AlterTableType
        AT_DropInherit,                         /* NO INHERIT parent */
        AT_AddOf,                                       /* OF <type_name> */
        AT_DropOf,                                      /* NOT OF */
-       AT_GenericOptions,                      /* OPTIONS (...) */
+       AT_GenericOptions                       /* OPTIONS (...) */
 } AlterTableType;
 
 typedef struct AlterTableCmd   /* one subcommand of an ALTER TABLE */
@@ -1234,7 +1234,6 @@ typedef struct AlterTableCmd      /* one subcommand of an ALTER TABLE */
                                                                 * constraint, or parent table */
        DropBehavior behavior;          /* RESTRICT or CASCADE for DROP cases */
        bool            missing_ok;             /* skip error if missing? */
-       bool            validated;
 } AlterTableCmd;
 
 
@@ -1469,8 +1468,9 @@ typedef struct CreateStmt
  *
  * If skip_validation is true then we skip checking that the existing rows
  * in the table satisfy the constraint, and just install the catalog entries
- * for the constraint. This is currently used only during CREATE TABLE
- * (when we know the table must be empty).
+ * for the constraint.  A new FK constraint is marked as valid iff
+ * initially_valid is true.  (Usually skip_validation and initially_valid
+ * are inverses, but we can set both true if the table is known empty.)
  *
  * Constraint attributes (DEFERRABLE etc) are initially represented as
  * separate Constraint nodes for simplicity of parsing.  parse_utilcmd.c makes
@@ -1544,7 +1544,7 @@ typedef struct Constraint
        char            fk_upd_action;  /* ON UPDATE action */
        char            fk_del_action;  /* ON DELETE action */
        bool            skip_validation;        /* skip validation of existing rows? */
-       bool            initially_valid;        /* start the new constraint as valid */
+       bool            initially_valid;        /* mark the new constraint as valid? */
 } Constraint;
 
 /* ----------------------
@@ -2417,7 +2417,7 @@ typedef enum VacuumOption
        VACOPT_VERBOSE = 1 << 2,        /* print progress info */
        VACOPT_FREEZE = 1 << 3,         /* FREEZE option */
        VACOPT_FULL = 1 << 4,           /* FULL (non-concurrent) vacuum */
-       VACOPT_NOWAIT = 1 << 5
+       VACOPT_NOWAIT = 1 << 5          /* don't wait to get lock (autovacuum only) */
 } VacuumOption;
 
 typedef struct VacuumStmt
index a689dbc..f6f9ff4 100644 (file)
@@ -207,12 +207,6 @@ ECPG: CopyStmtCOPYopt_binaryqualified_nameopt_column_listopt_oidscopy_fromcopy_f
 ECPG: CopyStmtCOPYselect_with_parensTOcopy_file_nameopt_withcopy_options addon
                        if (strcmp($4, "stdin") == 0)
                                mmerror(PARSE_ERROR, ET_ERROR, "COPY TO STDIN is not possible");
-ECPG: ConstraintAttributeSpecConstraintDeferrabilitySpecConstraintTimeSpec addon
-                       if (strcmp($1, "deferrable") != 0 && strcmp($2, "initially deferrable") == 0 )
-                               mmerror(PARSE_ERROR, ET_ERROR, "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
-ECPG: ConstraintAttributeSpecConstraintTimeSpecConstraintDeferrabilitySpec addon
-                       if (strcmp($2, "deferrable") != 0 && strcmp($1, "initially deferrable") == 0 )
-                               mmerror(PARSE_ERROR, ET_ERROR, "constraint declared INITIALLY DEFERRED must be DEFERRABLE");
 ECPG: var_valueNumericOnly addon
                if ($1[0] == '$')
                {