]> granicus.if.org Git - postgresql/commitdiff
Change syntax of new CHECK NO INHERIT constraints
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 24 Jul 2012 19:49:54 +0000 (15:49 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 24 Jul 2012 20:01:32 +0000 (16:01 -0400)
The initially implemented syntax, "CHECK NO INHERIT (expr)" was not
deemed very good, so switch to "CHECK (expr) NO INHERIT" instead.  This
way it looks similar to SQL-standards compliant constraint attribute.

Backport to 9.2 where the new syntax and feature was introduced.

Per discussion.

12 files changed:
doc/src/sgml/ref/alter_table.sgml
doc/src/sgml/ref/create_table.sgml
doc/src/sgml/release-9.2.sgml
src/backend/commands/typecmds.c
src/backend/parser/gram.y
src/backend/utils/adt/ruleutils.c
src/test/regress/expected/alter_table.out
src/test/regress/expected/inherit.out
src/test/regress/input/constraints.source
src/test/regress/output/constraints.source
src/test/regress/sql/alter_table.sql
src/test/regress/sql/inherit.sql

index 3f61d7d45fe457858924c8c03ac0b2103877609e..b7648142eea408a9990c2188b6a869f861d1168b 100644 (file)
@@ -495,7 +495,7 @@ ALTER TABLE [ IF EXISTS ] <replaceable class="PARAMETER">name</replaceable>
      <para>
       There must also be matching child-table constraints for all
       <literal>CHECK</literal> constraints of the parent, except those
-      marked non-inheritable (that is, created with <literal>ALTER TABLE ONLY</literal>)
+      marked non-inheritable (that is, created with <literal>ALTER TABLE ... ADD CONSTRAINT ... NO INHERIT</literal>)
       in the parent, which are ignored; all child-table constraints matched
       must not be marked non-inheritable.
       Currently
@@ -1013,7 +1013,7 @@ ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
   <para>
    To add a check constraint only to a table and not to its children:
 <programlisting>
-ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK NO INHERIT (char_length(zipcode) = 5);
+ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5) NO INHERIT;
 </programlisting>
    (The check constraint will not be inherited by future children, either.)
   </para>
index 08632d317271925775ee8171513209b1f45189aa..19e6f8ed6100e60eebf33243977f0488fc2d3aa1 100644 (file)
@@ -47,7 +47,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
 [ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
 { NOT NULL |
   NULL |
-  CHECK [ NO INHERIT ] ( <replaceable class="PARAMETER">expression</replaceable> ) |
+  CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) [ NO INHERIT ] |
   DEFAULT <replaceable>default_expr</replaceable> |
   UNIQUE <replaceable class="PARAMETER">index_parameters</replaceable> |
   PRIMARY KEY <replaceable class="PARAMETER">index_parameters</replaceable> |
@@ -58,7 +58,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
 <phrase>and <replaceable class="PARAMETER">table_constraint</replaceable> is:</phrase>
 
 [ CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ]
-{ CHECK [ NO INHERIT ] ( <replaceable class="PARAMETER">expression</replaceable> ) |
+{ CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) [ NO INHERIT ] |
   UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
   PRIMARY KEY ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] ) <replaceable class="PARAMETER">index_parameters</replaceable> |
   EXCLUDE [ USING <replaceable class="parameter">index_method</replaceable> ] ( <replaceable class="parameter">exclude_element</replaceable> WITH <replaceable class="parameter">operator</replaceable> [, ... ] ) <replaceable class="parameter">index_parameters</replaceable> [ WHERE ( <replaceable class="parameter">predicate</replaceable> ) ] |
@@ -417,7 +417,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
    </varlistentry>
 
    <varlistentry>
-    <term><literal>CHECK [ NO INHERIT ] ( <replaceable class="PARAMETER">expression</replaceable> )</literal></term>
+    <term><literal>CHECK ( <replaceable class="PARAMETER">expression</replaceable> ) [ NO INHERIT ] </literal></term>
     <listitem>
      <para>
       The <literal>CHECK</> clause specifies an expression producing a
index e79b0715000143f676b328a71d7655d85380ea4e..3ce80c22c2b4619786ea225355e50d99347b97f7 100644 (file)
       <listitem>
        <para>
         Allow <literal>CHECK</> constraints to be declared <literal>NO
-        INHERIT</> (Nikhil Sontakke, Alex Hunsaker)
+        INHERIT</> (Nikhil Sontakke, Alex Hunsaker, &Aacute;lvaro Herrera)
        </para>
 
        <para>
index 30850b2b22e20d9d916dddc92ee9db9584416f39..353043d581ac78c1bdf4b3972a8ba5dde3754ebf 100644 (file)
@@ -921,8 +921,14 @@ DefineDomain(CreateDomainStmt *stmt)
 
                                /*
                                 * Check constraints are handled after domain creation, as
-                                * they require the Oid of the domain
+                                * they require the Oid of the domain; at this point we can
+                                * only check that they're not marked NO INHERIT, because
+                                * that would be bogus.
                                 */
+                               if (constr->is_no_inherit)
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+                                                        errmsg("CHECK constraints for domains cannot be marked NO INHERIT")));
                                break;
 
                                /*
index 777da1139cd3275906c09274cfed678378022546..6b6901197db61ea2a560bd4bd4d186e78c8ddf84 100644 (file)
@@ -101,6 +101,7 @@ typedef struct PrivTarget
 #define CAS_INITIALLY_IMMEDIATE                0x04
 #define CAS_INITIALLY_DEFERRED         0x08
 #define CAS_NOT_VALID                          0x10
+#define CAS_NO_INHERIT                         0x20
 
 
 #define parser_yyerror(msg)  scanner_yyerror(msg, yyscanner)
@@ -144,7 +145,7 @@ static void SplitColQualList(List *qualList,
                                                         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);
+                          bool *no_inherit, core_yyscan_t yyscanner);
 
 %}
 
@@ -2709,13 +2710,13 @@ ColConstraintElem:
                                        n->indexspace = $4;
                                        $$ = (Node *)n;
                                }
-                       | CHECK opt_no_inherit '(' a_expr ')'
+                       | CHECK '(' a_expr ')' opt_no_inherit
                                {
                                        Constraint *n = makeNode(Constraint);
                                        n->contype = CONSTR_CHECK;
                                        n->location = @1;
-                                       n->is_no_inherit = $2;
-                                       n->raw_expr = $4;
+                                       n->is_no_inherit = $5;
+                                       n->raw_expr = $3;
                                        n->cooked_expr = NULL;
                                        $$ = (Node *)n;
                                }
@@ -2755,10 +2756,10 @@ ColConstraintElem:
  * combinations.
  *
  * See also ConstraintAttributeSpec, which can be used in places where
- * 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.)
+ * there is no parsing conflict.  (Note: currently, NOT VALID and NO INHERIT
+ * are allowed clauses in ConstraintAttributeSpec, but not here.  Someday we
+ * might need to allow them here too, but for the moment it doesn't seem
+ * useful in the statements that use ConstraintAttr.)
  */
 ConstraintAttr:
                        DEFERRABLE
@@ -2835,17 +2836,16 @@ TableConstraint:
                ;
 
 ConstraintElem:
-                       CHECK opt_no_inherit '(' a_expr ')' ConstraintAttributeSpec
+                       CHECK '(' a_expr ')' ConstraintAttributeSpec
                                {
                                        Constraint *n = makeNode(Constraint);
                                        n->contype = CONSTR_CHECK;
                                        n->location = @1;
-                                       n->is_no_inherit = $2;
-                                       n->raw_expr = $4;
+                                       n->raw_expr = $3;
                                        n->cooked_expr = NULL;
-                                       processCASbits($6, @6, "CHECK",
+                                       processCASbits($5, @5, "CHECK",
                                                                   NULL, NULL, &n->skip_validation,
-                                                                  yyscanner);
+                                                                  &n->is_no_inherit, yyscanner);
                                        n->initially_valid = !n->skip_validation;
                                        $$ = (Node *)n;
                                }
@@ -2861,7 +2861,7 @@ ConstraintElem:
                                        n->indexspace = $6;
                                        processCASbits($7, @7, "UNIQUE",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
                                        $$ = (Node *)n;
                                }
                        | UNIQUE ExistingIndex ConstraintAttributeSpec
@@ -2875,7 +2875,7 @@ ConstraintElem:
                                        n->indexspace = NULL;
                                        processCASbits($3, @3, "UNIQUE",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
                                        $$ = (Node *)n;
                                }
                        | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace
@@ -2890,7 +2890,7 @@ ConstraintElem:
                                        n->indexspace = $7;
                                        processCASbits($8, @8, "PRIMARY KEY",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
                                        $$ = (Node *)n;
                                }
                        | PRIMARY KEY ExistingIndex ConstraintAttributeSpec
@@ -2904,7 +2904,7 @@ ConstraintElem:
                                        n->indexspace = NULL;
                                        processCASbits($4, @4, "PRIMARY KEY",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
                                        $$ = (Node *)n;
                                }
                        | EXCLUDE access_method_clause '(' ExclusionConstraintList ')'
@@ -2922,7 +2922,7 @@ ConstraintElem:
                                        n->where_clause         = $8;
                                        processCASbits($9, @9, "EXCLUDE",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
                                        $$ = (Node *)n;
                                }
                        | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
@@ -2939,7 +2939,7 @@ ConstraintElem:
                                        n->fk_del_action        = (char) ($10 & 0xFF);
                                        processCASbits($11, @11, "FOREIGN KEY",
                                                                   &n->deferrable, &n->initdeferred,
-                                                                  &n->skip_validation,
+                                                                  &n->skip_validation, NULL,
                                                                   yyscanner);
                                        n->initially_valid = !n->skip_validation;
                                        $$ = (Node *)n;
@@ -4133,7 +4133,7 @@ CreateTrigStmt:
                                        n->isconstraint  = TRUE;
                                        processCASbits($10, @10, "TRIGGER",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
                                        n->constrrel = $9;
                                        $$ = (Node *)n;
                                }
@@ -4270,6 +4270,7 @@ ConstraintAttributeElem:
                        | INITIALLY IMMEDIATE                   { $$ = CAS_INITIALLY_IMMEDIATE; }
                        | INITIALLY DEFERRED                    { $$ = CAS_INITIALLY_DEFERRED; }
                        | NOT VALID                                             { $$ = CAS_NOT_VALID; }
+                       | NO INHERIT                                    { $$ = CAS_NO_INHERIT; }
                ;
 
 
@@ -4386,7 +4387,7 @@ CreateAssertStmt:
                                        n->isconstraint  = TRUE;
                                        processCASbits($8, @8, "ASSERTION",
                                                                   &n->deferrable, &n->initdeferred, NULL,
-                                                                  yyscanner);
+                                                                  NULL, yyscanner);
 
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -13380,7 +13381,7 @@ SplitColQualList(List *qualList,
 static void
 processCASbits(int cas_bits, int location, const char *constrType,
                           bool *deferrable, bool *initdeferred, bool *not_valid,
-                          core_yyscan_t yyscanner)
+                          bool *no_inherit, core_yyscan_t yyscanner)
 {
        /* defaults */
        if (deferrable)
@@ -13428,6 +13429,19 @@ processCASbits(int cas_bits, int location, const char *constrType,
                                                        constrType),
                                         parser_errposition(location)));
        }
+
+       if (cas_bits & CAS_NO_INHERIT)
+       {
+               if (no_inherit)
+                       *no_inherit = true;
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        /* translator: %s is CHECK, UNIQUE, or similar */
+                                        errmsg("%s constraints cannot be marked NO INHERIT",
+                                                       constrType),
+                                        parser_errposition(location)));
+       }
 }
 
 /* parser_init()
index ec93149f3e7987b8caf5f1b4fe38b66802ed258b..412dfe6f9aac5f49d618666866966809fb900e47 100644 (file)
@@ -1343,10 +1343,9 @@ pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
                                 * Note that simply checking for leading '(' and trailing ')'
                                 * would NOT be good enough, consider "(x > 0) AND (y > 0)".
                                 */
-                               appendStringInfo(&buf, "CHECK %s(%s)",
-                                                                conForm->connoinherit ? "NO INHERIT " : "",
-                                                                consrc);
-
+                               appendStringInfo(&buf, "CHECK (%s)%s",
+                                                                consrc,
+                                                                conForm->connoinherit ? " NO INHERIT" : "");
                                break;
                        }
                case CONSTRAINT_TRIGGER:
index c7dce415a60f8be9e2d172f3b55fefcaf529b4bc..453a3894b202873b31dada5727e7e09ae3f2f142 100644 (file)
@@ -233,7 +233,7 @@ Check constraints:
     "con1foo" CHECK (a > 0)
 Inherits: constraint_rename_test
 
-ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK NO INHERIT (b > 0);
+ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT;
 ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok
 ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok
 \d constraint_rename_test
@@ -245,7 +245,7 @@ Table "public.constraint_rename_test"
  c      | integer | 
 Check constraints:
     "con1foo" CHECK (a > 0)
-    "con2bar" CHECK NO INHERIT (b > 0)
+    "con2bar" CHECK (b > 0) NO INHERIT
 Number of child tables: 1 (Use \d+ to list them.)
 
 \d constraint_rename_test2
@@ -273,7 +273,7 @@ Indexes:
     "con3foo" PRIMARY KEY, btree (a)
 Check constraints:
     "con1foo" CHECK (a > 0)
-    "con2bar" CHECK NO INHERIT (b > 0)
+    "con2bar" CHECK (b > 0) NO INHERIT
 Number of child tables: 1 (Use \d+ to list them.)
 
 \d constraint_rename_test2
@@ -635,7 +635,7 @@ drop table atacc1;
 create table atacc1 (test int);
 create table atacc2 (test2 int) inherits (atacc1);
 -- ok:
-alter table atacc1 add constraint foo check no inherit (test>0);
+alter table atacc1 add constraint foo check (test>0) no inherit;
 -- check constraint is not there on child
 insert into atacc2 (test) values (-3);
 -- check constraint is there on parent
@@ -644,7 +644,7 @@ ERROR:  new row for relation "atacc1" violates check constraint "foo"
 DETAIL:  Failing row contains (-3).
 insert into atacc1 (test) values (3);
 -- fail, violating row:
-alter table atacc2 add constraint foo check no inherit (test>0);
+alter table atacc2 add constraint foo check (test>0) no inherit;
 ERROR:  check constraint "foo" is violated by some row
 drop table atacc2;
 drop table atacc1;
index c178e256078ff16e8d3b1e3da0b99da33bc14af8..25adcd2346118853ef57943bd22d9b80667ca560 100644 (file)
@@ -597,7 +597,7 @@ select * from d;
 
 -- Test non-inheritable parent constraints
 create table p1(ff1 int);
-alter table p1 add constraint p1chk check no inherit (ff1 > 0);
+alter table p1 add constraint p1chk check (ff1 > 0) no inherit;
 alter table p1 add constraint p2chk check (ff1 > 10);
 -- connoinherit should be true for NO INHERIT constraint
 select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.connoinherit from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2;
@@ -615,7 +615,7 @@ create table c1 () inherits (p1);
 --------+---------+-----------
  ff1    | integer | 
 Check constraints:
-    "p1chk" CHECK NO INHERIT (ff1 > 0)
+    "p1chk" CHECK (ff1 > 0) NO INHERIT
     "p2chk" CHECK (ff1 > 10)
 Number of child tables: 1 (Use \d+ to list them.)
 
index 37d06b0127aa0702dd75c9235f2e7da3b5daa305..16468b20afb599e90f354b6269ac3f9acf4feeec 100644 (file)
@@ -148,7 +148,7 @@ DROP TABLE INSERT_CHILD;
 --
 
 CREATE TABLE ATACC1 (TEST INT
-       CHECK NO INHERIT (TEST > 0));
+       CHECK (TEST > 0) NO INHERIT);
 
 CREATE TABLE ATACC2 (TEST2 INT) INHERITS (ATACC1);
 -- check constraint is not there on child
@@ -158,7 +158,7 @@ INSERT INTO ATACC1 (TEST) VALUES (-3);
 DROP TABLE ATACC1 CASCADE;
 
 CREATE TABLE ATACC1 (TEST INT, TEST2 INT
-       CHECK (TEST > 0), CHECK NO INHERIT (TEST2 > 10));
+       CHECK (TEST > 0), CHECK (TEST2 > 10) NO INHERIT);
 
 CREATE TABLE ATACC2 () INHERITS (ATACC1);
 -- check constraint is there on child
index e8237f4a693657fdb15263cafcaa2f5abb539d2d..ff6c1dc450d2cfeabb2c849a0d2e81ad615bb5ac 100644 (file)
@@ -231,7 +231,7 @@ DROP TABLE INSERT_CHILD;
 -- Check NO INHERIT type of constraints and inheritance
 --
 CREATE TABLE ATACC1 (TEST INT
-       CHECK NO INHERIT (TEST > 0));
+       CHECK (TEST > 0) NO INHERIT);
 CREATE TABLE ATACC2 (TEST2 INT) INHERITS (ATACC1);
 -- check constraint is not there on child
 INSERT INTO ATACC2 (TEST) VALUES (-3);
@@ -242,7 +242,7 @@ DETAIL:  Failing row contains (-3).
 DROP TABLE ATACC1 CASCADE;
 NOTICE:  drop cascades to table atacc2
 CREATE TABLE ATACC1 (TEST INT, TEST2 INT
-       CHECK (TEST > 0), CHECK NO INHERIT (TEST2 > 10));
+       CHECK (TEST > 0), CHECK (TEST2 > 10) NO INHERIT);
 CREATE TABLE ATACC2 () INHERITS (ATACC1);
 -- check constraint is there on child
 INSERT INTO ATACC2 (TEST) VALUES (-3);
index 5ca537e91bcbe33d8e2792d552ba6b0592c6e97b..0f9cb380e1662749295cc2fca959346a8d1b84c6 100644 (file)
@@ -218,7 +218,7 @@ ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- fa
 ALTER TABLE constraint_rename_test RENAME CONSTRAINT con1 TO con1foo; -- ok
 \d constraint_rename_test
 \d constraint_rename_test2
-ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK NO INHERIT (b > 0);
+ALTER TABLE constraint_rename_test ADD CONSTRAINT con2 CHECK (b > 0) NO INHERIT;
 ALTER TABLE ONLY constraint_rename_test RENAME CONSTRAINT con2 TO con2foo; -- ok
 ALTER TABLE constraint_rename_test RENAME CONSTRAINT con2foo TO con2bar; -- ok
 \d constraint_rename_test
@@ -500,14 +500,14 @@ drop table atacc1;
 create table atacc1 (test int);
 create table atacc2 (test2 int) inherits (atacc1);
 -- ok:
-alter table atacc1 add constraint foo check no inherit (test>0);
+alter table atacc1 add constraint foo check (test>0) no inherit;
 -- check constraint is not there on child
 insert into atacc2 (test) values (-3);
 -- check constraint is there on parent
 insert into atacc1 (test) values (-3);
 insert into atacc1 (test) values (3);
 -- fail, violating row:
-alter table atacc2 add constraint foo check no inherit (test>0);
+alter table atacc2 add constraint foo check (test>0) no inherit;
 drop table atacc2;
 drop table atacc1;
 
index 74cb3f09e8573f399f7d79cf74ebe0ad141a2e32..29c1e59fd0a84685c9a8236c6e02ded6869da764 100644 (file)
@@ -140,7 +140,7 @@ select * from d;
 
 -- Test non-inheritable parent constraints
 create table p1(ff1 int);
-alter table p1 add constraint p1chk check no inherit (ff1 > 0);
+alter table p1 add constraint p1chk check (ff1 > 0) no inherit;
 alter table p1 add constraint p2chk check (ff1 > 10);
 -- connoinherit should be true for NO INHERIT constraint
 select pc.relname, pgc.conname, pgc.contype, pgc.conislocal, pgc.coninhcount, pgc.connoinherit from pg_class as pc inner join pg_constraint as pgc on (pgc.conrelid = pc.oid) where pc.relname = 'p1' order by 1,2;