This is a complete patch to implement changing the nullability of an
attribute.  It passes all regressions tests.  It includes its own quite
comprehensive regression test suite and documentation.  It prevents you from
modifying system tables, non-table relations, system attributes, primary
keys and columns containing NULLs.  It fully supports inheritance.  I have
made some small changes to TODO to reflect this new functionality, plus
corrected some other TODO items.

The only thing I haven't checked are my ecpg changes.  I would like someone
with more ecpg experience to check my preproc.y changes.

Please consider for 7.3!

Since I have now added two new large functions to command.c, I propose that
sometime before 7.3 beta, command.c is refactored and an alter.c created.
There is lots of common code in the Alter* functions that should be reused.

Chris
? GNUmakefile
? alpha-patch.txt
? config.cache
? config.log
? config.status
? configure.out
? domaintest.sql
? null.txt
? regression.txt
? contrib/tree
? contrib/tree.tar.gz
? contrib/intagg/int_aggregate.sql
? src/GNUmakefile
? src/Makefile.global
? src/backend/postgres
? src/backend/catalog/postgres.bki
? src/backend/catalog/postgres.description
? src/bin/initdb/initdb
? src/bin/initlocation/initlocation
? src/bin/ipcclean/ipcclean
? src/bin/pg_config/pg_config
? src/bin/pg_ctl/pg_ctl
? src/bin/pg_dump/pg_dump
? src/bin/pg_dump/pg_dumpall
? src/bin/pg_dump/pg_restore
? src/bin/pg_id/pg_id
? src/bin/pg_passwd/pg_passwd
? src/bin/psql/psql
? src/bin/scripts/createlang
? src/include/pg_config.h
? src/include/stamp-h
? src/interfaces/ecpg/lib/libecpg.so.3
? src/interfaces/ecpg/preproc/ecpg
? src/interfaces/libpgeasy/libpgeasy.so.2
? src/interfaces/libpq/libpq.so.2
? src/pl/plpgsql/src/libplpgsql.so.1
? src/test/regress/log
? src/test/regress/pg_regress
? src/test/regress/postgres.core
? src/test/regress/results
? src/test/regress/tmp_check
? src/test/regress/expected/bak.out
? src/test/regress/expected/constraints.out
? src/test/regress/expected/copy.out
? src/test/regress/expected/create_function_1.out
? src/test/regress/expected/create_function_2.out
? src/test/regress/expected/misc.out
? src/test/regress/sql/constraints.sql
? src/test/regress/sql/copy.sql
? src/test/regress/sql/create_function_1.sql
? src/test/regress/sql/create_function_2.sql
? src/test/regress/sql/misc.sql
Index: doc/TODO
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/TODO,v
retrieving revision 1.775
diff -c -r1.775 TODO
*** doc/TODO    2002/03/25 20:56:08     1.775
--- doc/TODO    2002/03/27 06:12:03
***************
*** 185,192 ****
        o Add ALTER TABLE DROP COLUMN feature [drop] (Bruce)
        o Add ALTER FUNCTION
        o Add ALTER TABLE DROP non-CHECK CONSTRAINT
!       o ALTER TABLE ADD PRIMARY KEY (Christopher Kings-Lynne)
!       o ALTER TABLE ADD UNIQUE (Christopher Kings-Lynne)
        o ALTER TABLE ADD COLUMN column SERIAL doesn't create sequence
        o ALTER TABLE ADD COLUMN column SET DEFAULT should fill existing
          rows with DEFAULT value
--- 185,193 ----
        o Add ALTER TABLE DROP COLUMN feature [drop] (Bruce)
        o Add ALTER FUNCTION
        o Add ALTER TABLE DROP non-CHECK CONSTRAINT
!       o -ALTER TABLE ADD PRIMARY KEY (Tom)
!       o -ALTER TABLE ADD UNIQUE (Tom)
!       o -ALTER TABLE ALTER COLUMN SET/DROP NOT NULL (Christopher Kings-Lynne)
        o ALTER TABLE ADD COLUMN column SERIAL doesn't create sequence
        o ALTER TABLE ADD COLUMN column SET DEFAULT should fill existing
          rows with DEFAULT value
Index: doc/src/sgml/ref/alter_table.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v
retrieving revision 1.40
diff -c -r1.40 alter_table.sgml
*** doc/src/sgml/ref/alter_table.sgml   2002/03/06 20:42:38     1.40
--- doc/src/sgml/ref/alter_table.sgml   2002/03/27 06:12:03
***************
*** 29,34 ****
--- 29,36 ----
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET 
DEFAULT <replaceable
      class="PARAMETER">value</replaceable> | DROP DEFAULT }
  ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
+     ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET | 
+DROP } NOT NULL
+ ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET 
STATISTICS <replaceable class="PARAMETER">integer</replaceable>
  ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
      ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STORAGE 
{PLAIN | EXTERNAL | EXTENDED | MAIN}
***************
*** 168,173 ****
--- 170,178 ----
     allow you to set or remove the default for the column. Note that defaults
     only apply to subsequent <command>INSERT</command> commands; they do not
     cause rows already in the table to change.
+    The <literal>ALTER COLUMN SET/DROP NOT NULL</literal> forms allow you to
+    change whether a column is marked to allow NULL values or to reject NULL
+    values.
     The <literal>ALTER COLUMN SET STATISTICS</literal> form allows you to
     set the statistics-gathering target for subsequent
     <xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
***************
*** 276,281 ****
--- 281,297 ----
     To rename an existing table:
     <programlisting>
  ALTER TABLE distributors RENAME TO suppliers;
+    </programlisting>
+   </para>
+ 
+   <para>
+    To add a NOT NULL constraint to a column:
+    <programlisting>
+ ALTER TABLE distributors ALTER COLUMN street SET NOT NULL;
+    </programlisting>
+    To remove a NOT NULL constraint from a column:
+    <programlisting>
+ ALTER TABLE distributors ALTER COLUMN street DROP NOT NULL;
     </programlisting>
    </para>
  
Index: src/backend/commands/command.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/command.c,v
retrieving revision 1.166
diff -c -r1.166 command.c
*** src/backend/commands/command.c      2002/03/26 19:15:36     1.166
--- src/backend/commands/command.c      2002/03/27 06:12:06
***************
*** 544,549 ****
--- 544,861 ----
        AlterTableCreateToastTable(myrelid, true);
  }
  
+ /*
+  * ALTER TABLE ALTER COLUMN DROP NOT NULL
+  */
+ void
+ AlterTableAlterColumnDropNotNull(const char *relationName,
+                                                       bool inh, const char *colName)
+ {
+       Relation        rel;
+       HeapTuple       tuple;
+       int16           attnum;
+       Oid             myrelid;
+       Relation        attr_rel;
+       ScanKeyData     scankeys[3];
+       HeapScanDesc    scan;
+       List            *indexoidlist;
+       List            *indexoidscan;
+ 
+       rel = heap_openr(relationName, AccessExclusiveLock);
+       myrelid = RelationGetRelid(rel);
+ 
+       if (rel->rd_rel->relkind != RELKIND_RELATION)
+               elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
+                        relationName);
+ 
+       if (!allowSystemTableMods && IsSystemRelationName(relationName))
+               elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
+                        relationName);
+       if (!pg_class_ownercheck(myrelid, GetUserId()))
+               elog(ERROR, "ALTER TABLE: permission denied");
+ 
+       heap_close(rel, NoLock);
+ 
+       /*
+        * Propagate to children if desired
+        */
+       if (inh)
+       {
+               List       *child,
+                                  *children;
+ 
+               /* this routine is actually in the planner */
+               children = find_all_inheritors(myrelid);
+ 
+               /*
+                * find_all_inheritors does the recursive search of the
+                * inheritance hierarchy, so all we have to do is process all of
+                * the relids in the list that it returns.
+                */
+               foreach(child, children)
+               {
+                       Oid                     childrelid = lfirsti(child);
+ 
+                       if (childrelid == myrelid)
+                               continue;
+                       rel = heap_open(childrelid, AccessExclusiveLock);
+                       AlterTableAlterColumnDropNotNull(RelationGetRelationName(rel),
+                                                                                
+false, colName);
+                       heap_close(rel, AccessExclusiveLock);
+               }
+       }
+ 
+       /* -= now do the thing on this relation =- */
+ 
+       /* reopen the business */
+       rel = heap_openr(relationName, AccessExclusiveLock);
+ 
+       /*
+        * get the number of the attribute
+        */
+       tuple = SearchSysCache(ATTNAME,
+                                                  ObjectIdGetDatum(myrelid),
+                                                  PointerGetDatum(colName),
+                                                  0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
+                        relationName, colName);
+ 
+       attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
+       ReleaseSysCache(tuple);
+ 
+       /* Prevent them from altering a system attribute */
+       if (attnum < 0)
+               elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
+                       colName);
+ 
+       /* 
+        * Check that the attribute is not in a primary key
+        */
+               
+       /* Loop over all indices on the relation */
+       indexoidlist = RelationGetIndexList(rel);
+ 
+       foreach(indexoidscan, indexoidlist)
+       {
+               Oid             indexoid = lfirsti(indexoidscan);
+               HeapTuple       indexTuple;
+               Form_pg_index   indexStruct;
+               int             i;
+ 
+               indexTuple = SearchSysCache(INDEXRELID,
+                                 ObjectIdGetDatum(indexoid),
+                                                                       0, 0, 0);
+ 
+               if (!HeapTupleIsValid(indexTuple))
+                       elog(ERROR, "ALTER TABLE: Index \"%u\" not found",
+                                indexoid);
+               indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
+ 
+               /* If the index is not a primary key, skip the check */
+               if (!indexStruct->indisprimary) continue;
+ 
+               /*
+                * Loop over each attribute in the primary key and
+                * see if it matches the to-be-altered attribute
+                */
+               for (i = 0; i < INDEX_MAX_KEYS &&
+                            indexStruct->indkey[i] != InvalidAttrNumber; i++)
+               {
+                       if (indexStruct->indkey[i] == attnum)
+                               elog(ERROR, "ALTER TABLE: Attribute \"%s\" is in a 
+primary key", colName);
+               }
+       
+               ReleaseSysCache(indexTuple);
+       }
+ 
+       freeList(indexoidlist);
+ 
+       /*
+        * Now, actually perform the catalog change
+        */
+       attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
+       ScanKeyEntryInitialize(&scankeys[0], 0x0,
+                                                  Anum_pg_attribute_attrelid, F_OIDEQ,
+                                                  ObjectIdGetDatum(myrelid));
+       ScanKeyEntryInitialize(&scankeys[1], 0x0,
+                                                  Anum_pg_attribute_attnum, F_INT2EQ,
+                                                  Int16GetDatum(attnum));
+       ScanKeyEntryInitialize(&scankeys[2], 0x0,
+                                                  Anum_pg_attribute_attnotnull, 
+F_BOOLEQ,
+                                                  BoolGetDatum(true));
+ 
+       scan = heap_beginscan(attr_rel, false, SnapshotNow, 3, scankeys);
+       AssertState(scan != NULL);
+ 
+       if (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+       {
+               HeapTuple       newtuple;
+               Relation        irelations[Num_pg_attr_indices];
+ 
+               /* update to false */
+               newtuple = heap_copytuple(tuple);
+               ((Form_pg_attribute) GETSTRUCT(newtuple))->attnotnull = FALSE;
+               simple_heap_update(attr_rel, &tuple->t_self, newtuple);
+ 
+               /* keep the system catalog indices current */
+               CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, 
+irelations);
+               CatalogIndexInsert(irelations, Num_pg_attr_indices, attr_rel, 
+newtuple);
+               CatalogCloseIndices(Num_pg_attr_indices, irelations);
+       }
+ 
+       heap_endscan(scan);
+       heap_close(attr_rel, NoLock);
+ 
+       heap_close(rel, NoLock);
+ }
+ 
+ /*
+  * ALTER TABLE ALTER COLUMN SET NOT NULL
+  */
+ void
+ AlterTableAlterColumnNotNull(const char *relationName,
+                                                       bool inh, const char *colName)
+ {
+       Relation        rel;
+       HeapTuple       tuple;
+       int16           attnum;
+       Oid             myrelid;
+       Relation        attr_rel;
+       ScanKeyData     scankeys[3];
+       HeapScanDesc    scan;
+       /* variables for table scan */  
+       bool            isnull = false;
+       TupleDesc       tupdesc;
+       Datum           d;
+ 
+       rel = heap_openr(relationName, AccessExclusiveLock);
+       myrelid = RelationGetRelid(rel);
+ 
+       if (rel->rd_rel->relkind != RELKIND_RELATION)
+               elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
+                        relationName);
+ 
+       if (!allowSystemTableMods && IsSystemRelationName(relationName))
+               elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
+                        relationName);
+       if (!pg_class_ownercheck(myrelid, GetUserId()))
+               elog(ERROR, "ALTER TABLE: permission denied");
+ 
+       heap_close(rel, NoLock);
+ 
+       /*
+        * Propagate to children if desired
+        */
+       if (inh)
+       {
+               List       *child,
+                                  *children;
+ 
+               /* this routine is actually in the planner */
+               children = find_all_inheritors(myrelid);
+ 
+               /*
+                * find_all_inheritors does the recursive search of the
+                * inheritance hierarchy, so all we have to do is process all of
+                * the relids in the list that it returns.
+                */
+               foreach(child, children)
+               {
+                       Oid                     childrelid = lfirsti(child);
+ 
+                       if (childrelid == myrelid)
+                               continue;
+                       rel = heap_open(childrelid, AccessExclusiveLock);
+                       AlterTableAlterColumnNotNull(RelationGetRelationName(rel),
+                                                                                
+false, colName);
+                       heap_close(rel, AccessExclusiveLock);
+               }
+       }
+ 
+       /* -= now do the thing on this relation =- */
+ 
+       /* reopen the business */
+       rel = heap_openr(relationName, AccessExclusiveLock);
+       tupdesc = RelationGetDescr(rel);
+ 
+       /*
+        * get the number of the attribute
+        */
+       tuple = SearchSysCache(ATTNAME,
+                                                  ObjectIdGetDatum(myrelid),
+                                                  PointerGetDatum(colName),
+                                                  0, 0);
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
+                        relationName, colName);
+ 
+       attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
+       ReleaseSysCache(tuple);
+ 
+       /* Prevent them from altering a system attribute */
+       if (attnum < 0)
+               elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"",
+                       colName);
+ 
+       /*
+        * Perform a scan to ensure that there are no NULL
+        * values already in the relation
+        */
+ 
+       scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
+ 
+       while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+       {
+               d = heap_getattr(tuple, attnum, tupdesc, &isnull);
+ 
+               if (isnull)
+                       elog(ERROR, "ALTER TABLE: Attribute \"%s\" contains NULL 
+values", colName);
+       }
+ 
+       heap_endscan(scan);
+ 
+       /*
+        * Update attribute to be NOT NULL
+        */
+        
+       attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
+       ScanKeyEntryInitialize(&scankeys[0], 0x0,
+                                                  Anum_pg_attribute_attrelid, F_OIDEQ,
+                                                  ObjectIdGetDatum(myrelid));
+       ScanKeyEntryInitialize(&scankeys[1], 0x0,
+                                                  Anum_pg_attribute_attnum, F_INT2EQ,
+                                                  Int16GetDatum(attnum));
+       ScanKeyEntryInitialize(&scankeys[2], 0x0,
+                                                  Anum_pg_attribute_attnotnull, 
+F_BOOLEQ,
+                                                  BoolGetDatum(false));
+ 
+       scan = heap_beginscan(attr_rel, false, SnapshotNow, 3, scankeys);
+       AssertState(scan != NULL);
+ 
+       if (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+       {
+               HeapTuple       newtuple;
+               Relation        irelations[Num_pg_attr_indices];
+ 
+               /* update to false */
+               newtuple = heap_copytuple(tuple);
+               ((Form_pg_attribute) GETSTRUCT(newtuple))->attnotnull = TRUE;
+               simple_heap_update(attr_rel, &tuple->t_self, newtuple);
+ 
+               /* keep the system catalog indices current */
+               CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, 
+irelations);
+               CatalogIndexInsert(irelations, Num_pg_attr_indices, attr_rel, 
+newtuple);
+               CatalogCloseIndices(Num_pg_attr_indices, irelations);
+       }
+ 
+       heap_endscan(scan);
+       heap_close(attr_rel, NoLock);
+ 
+       heap_close(rel, NoLock);                
+ }
+ 
+ 
  
  /*
   * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.296
diff -c -r2.296 gram.y
*** src/backend/parser/gram.y   2002/03/22 02:56:33     2.296
--- src/backend/parser/gram.y   2002/03/27 06:12:13
***************
*** 1114,1119 ****
--- 1114,1137 ----
                                        n->def = $7;
                                        $$ = (Node *)n;
                                }
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> DROP NOT NULL */
+                 | ALTER TABLE relation_expr ALTER opt_column ColId DROP NOT NULL_P
+                                 {
+                                         AlterTableStmt *n = makeNode(AlterTableStmt);
+                                         n->subtype = 'N';
+                                         n->relation = $3;
+                                         n->name = $6;
+                                         $$ = (Node *)n;
+                                 }
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET NOT NULL */
+                 | ALTER TABLE relation_expr ALTER opt_column ColId SET NOT NULL_P
+                                 {
+                                         AlterTableStmt *n = makeNode(AlterTableStmt);
+                                         n->subtype = 'O';
+                                         n->relation = $3;
+                                         n->name = $6;
+                                         $$ = (Node *)n;
+                                 }
  /* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET STATISTICS <Iconst> */
                | ALTER TABLE relation_expr ALTER opt_column ColId SET STATISTICS 
Iconst
                                {
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.140
diff -c -r1.140 utility.c
*** src/backend/tcop/utility.c  2002/03/26 19:16:03     1.140
--- src/backend/tcop/utility.c  2002/03/27 06:12:14
***************
*** 439,444 ****
--- 439,454 ----
                                                                                       
                  stmt->name,
                                                                                       
                  stmt->def);
                                                break;
+                                       case 'N':       /* ALTER COLUMN DROP NOT NULL 
+*/
+                                               
+AlterTableAlterColumnDropNotNull(stmt->relation->relname,
+                                                                               
+interpretInhOption((stmt->relation)->inhOpt),
+                                                                                      
+                 stmt->name);
+                                               break;
+                                       case 'O':       /* ALTER COLUMN SET NOT NULL */
+                                               
+AlterTableAlterColumnNotNull(stmt->relation->relname,
+                                                                               
+interpretInhOption((stmt->relation)->inhOpt),
+                                                                                      
+                 stmt->name);
+                                               break;
                                        case 'S':       /* ALTER COLUMN STATISTICS */
                                        case 'M':   /* ALTER COLUMN STORAGE */
                                                
AlterTableAlterColumnFlags(stmt->relation->relname,
Index: src/include/commands/command.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/commands/command.h,v
retrieving revision 1.35
diff -c -r1.35 command.h
*** src/include/commands/command.h      2002/03/26 19:16:40     1.35
--- src/include/commands/command.h      2002/03/27 06:12:15
***************
*** 47,52 ****
--- 47,58 ----
                                                         bool inh, const char *colName,
                                                         Node *newDefault);
  
+ extern void AlterTableAlterColumnDropNotNull(const char *relationName,
+                                                        bool inh, const char 
+*colName);
+ 
+ extern void AlterTableAlterColumnNotNull(const char *relationName,
+                                                        bool inh, const char 
+*colName);
+ 
  extern void AlterTableAlterColumnFlags(const char *relationName,
                                                                bool inh, const char 
*colName,
                                                                Node *flagValue, const 
char *flagType);
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.165
diff -c -r1.165 parsenodes.h
*** src/include/nodes/parsenodes.h      2002/03/26 19:16:53     1.165
--- src/include/nodes/parsenodes.h      2002/03/27 06:12:17
***************
*** 719,724 ****
--- 719,726 ----
        char            subtype;                /*------------
                                                                 *      A = add column
                                                                 *      T = alter 
column default
+                                                                *      N = alter 
+column drop not null
+                                                                *      O = alter 
+column set not null
                                                                 *      S = alter 
column statistics
                                                                 *  M = alter column 
storage
                                                                 *      D = drop column
Index: src/interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.184
diff -c -r1.184 preproc.y
*** src/interfaces/ecpg/preproc/preproc.y       2002/03/21 09:42:50     1.184
--- src/interfaces/ecpg/preproc/preproc.y       2002/03/27 06:12:23
***************
*** 907,912 ****
--- 907,918 ----
  /* ALTER TABLE <relation> ALTER [COLUMN] <colname> {SET DEFAULT <expr>|DROP DEFAULT} 
*/
                | ALTER TABLE relation_expr ALTER opt_column ColId alter_column_default
                        { $$ = cat_str(6, make_str("alter table"), $3, 
make_str("alter"), $5, $6, $7); }
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> DROP NOT NULL */
+               | ALTER TABLE relation_expr ALTER opt_column ColId DROP NOT NULL_P
+                       { $$ = cat_str(5, make_str("alter table"), $3, 
+make_str("alter"), $5, $6); }
+ /* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET NOT NULL */
+               | ALTER TABLE relation_expr ALTER opt_column ColId SET NOT NULL_P
+                       { $$ = cat_str(5, make_str("alter table"), $3, 
+make_str("alter"), $5, $6); }
  /* ALTER TABLE <relation> ALTER [COLUMN] <colname> SET STATISTICS <Iconst> */
                | ALTER TABLE relation_expr ALTER opt_column ColId SET STATISTICS 
Iconst
                        { $$ = cat_str(7, make_str("alter table"), $3, 
make_str("alter"), $5, $6, make_str("set statistics"), $9); }
Index: src/test/regress/expected/alter_table.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/alter_table.out,v
retrieving revision 1.34
diff -c -r1.34 alter_table.out
*** src/test/regress/expected/alter_table.out   2002/03/21 16:02:09     1.34
--- src/test/regress/expected/alter_table.out   2002/03/27 06:12:24
***************
*** 578,580 ****
--- 578,651 ----
  insert into atacc1 (test2, test) values (1, NULL);
  ERROR:  ExecAppend: Fail to add null value in not null attribute test
  drop table atacc1;
+ -- alter table / alter column [set/drop] not null tests
+ -- try altering system catalogs, should fail
+ alter table pg_class alter column relname drop not null;
+ ERROR:  ALTER TABLE: relation "pg_class" is a system catalog
+ alter table pg_class alter relname set not null;
+ ERROR:  ALTER TABLE: relation "pg_class" is a system catalog
+ -- try altering non-existent table, should fail
+ alter table foo alter column bar set not null;
+ ERROR:  Relation "foo" does not exist
+ alter table foo alter column bar drop not null;
+ ERROR:  Relation "foo" does not exist
+ -- test setting columns to null and not null and vice versa
+ -- test checking for null values and primary key
+ create table atacc1 (test int not null);
+ alter table atacc1 add constraint "atacc1_pkey" primary key (test);
+ NOTICE:  ALTER TABLE / ADD PRIMARY KEY will create implicit index 'atacc1_pkey' for 
+table 'atacc1'
+ alter table atacc1 alter column test drop not null;
+ ERROR:  ALTER TABLE: Attribute "test" is in a primary key
+ drop index atacc1_pkey;
+ alter table atacc1 alter column test drop not null;
+ insert into atacc1 values (null);
+ alter table atacc1 alter test set not null;
+ ERROR:  ALTER TABLE: Attribute "test" contains NULL values
+ delete from atacc1;
+ alter table atacc1 alter test set not null;
+ -- try altering a non-existent column, should fail
+ alter table atacc1 alter bar set not null;
+ ERROR:  ALTER TABLE: relation "atacc1" has no column "bar"
+ alter table atacc1 alter bar drop not null;
+ ERROR:  ALTER TABLE: relation "atacc1" has no column "bar"
+ -- try altering the oid column, should fail
+ alter table atacc1 alter oid set not null;
+ ERROR:  ALTER TABLE: Cannot alter system attribute "oid"
+ alter table atacc1 alter oid drop not null;
+ ERROR:  ALTER TABLE: Cannot alter system attribute "oid"
+ -- try creating a view and altering that, should fail
+ create view myview as select * from atacc1;
+ alter table myview alter column test drop not null;
+ ERROR:  ALTER TABLE: relation "myview" is not a table
+ alter table myview alter column test set not null;
+ ERROR:  ALTER TABLE: relation "myview" is not a table
+ drop view myview;
+ drop table atacc1;
+ -- test inheritance
+ create table parent (a int);
+ create table child (b varchar(255)) inherits (parent);
+ alter table parent alter a set not null;
+ insert into parent values (NULL);
+ ERROR:  ExecAppend: Fail to add null value in not null attribute a
+ insert into child (a, b) values (NULL, 'foo');
+ ERROR:  ExecAppend: Fail to add null value in not null attribute a
+ alter table parent alter a drop not null;
+ insert into parent values (NULL);
+ insert into child (a, b) values (NULL, 'foo');
+ alter table only parent alter a set not null;
+ ERROR:  ALTER TABLE: Attribute "a" contains NULL values
+ alter table child alter a set not null;
+ ERROR:  ALTER TABLE: Attribute "a" contains NULL values
+ delete from parent;
+ alter table only parent alter a set not null;
+ insert into parent values (NULL);
+ ERROR:  ExecAppend: Fail to add null value in not null attribute a
+ alter table child alter a set not null;
+ insert into child (a, b) values (NULL, 'foo');
+ ERROR:  ExecAppend: Fail to add null value in not null attribute a
+ delete from child;
+ alter table child alter a set not null;
+ insert into child (a, b) values (NULL, 'foo');
+ ERROR:  ExecAppend: Fail to add null value in not null attribute a
+ drop table child;
+ drop table parent;
Index: src/test/regress/sql/alter_table.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/alter_table.sql,v
retrieving revision 1.21
diff -c -r1.21 alter_table.sql
*** src/test/regress/sql/alter_table.sql        2002/03/19 12:59:08     1.21
--- src/test/regress/sql/alter_table.sql        2002/03/27 06:12:25
***************
*** 452,454 ****
--- 452,515 ----
  insert into atacc1 (test2, test) values (2, 3);
  insert into atacc1 (test2, test) values (1, NULL);
  drop table atacc1;
+ 
+ -- alter table / alter column [set/drop] not null tests
+ -- try altering system catalogs, should fail
+ alter table pg_class alter column relname drop not null;
+ alter table pg_class alter relname set not null;
+ 
+ -- try altering non-existent table, should fail
+ alter table foo alter column bar set not null;
+ alter table foo alter column bar drop not null;
+ 
+ -- test setting columns to null and not null and vice versa
+ -- test checking for null values and primary key
+ create table atacc1 (test int not null);
+ alter table atacc1 add constraint "atacc1_pkey" primary key (test);
+ alter table atacc1 alter column test drop not null;
+ drop index atacc1_pkey;
+ alter table atacc1 alter column test drop not null;
+ insert into atacc1 values (null);
+ alter table atacc1 alter test set not null;
+ delete from atacc1;
+ alter table atacc1 alter test set not null;
+ 
+ -- try altering a non-existent column, should fail
+ alter table atacc1 alter bar set not null;
+ alter table atacc1 alter bar drop not null;
+ 
+ -- try altering the oid column, should fail
+ alter table atacc1 alter oid set not null;
+ alter table atacc1 alter oid drop not null;
+ 
+ -- try creating a view and altering that, should fail
+ create view myview as select * from atacc1;
+ alter table myview alter column test drop not null;
+ alter table myview alter column test set not null;
+ drop view myview;
+ 
+ drop table atacc1;
+ 
+ -- test inheritance
+ create table parent (a int);
+ create table child (b varchar(255)) inherits (parent);
+ 
+ alter table parent alter a set not null;
+ insert into parent values (NULL);
+ insert into child (a, b) values (NULL, 'foo');
+ alter table parent alter a drop not null;
+ insert into parent values (NULL);
+ insert into child (a, b) values (NULL, 'foo');
+ alter table only parent alter a set not null;
+ alter table child alter a set not null;
+ delete from parent;
+ alter table only parent alter a set not null;
+ insert into parent values (NULL);
+ alter table child alter a set not null;
+ insert into child (a, b) values (NULL, 'foo');
+ delete from child;
+ alter table child alter a set not null;
+ insert into child (a, b) values (NULL, 'foo');
+ drop table child;
+ drop table parent;
+ 

---------------------------(end of broadcast)---------------------------
TIP 2: you can get off all lists at once with the unregister command
    (send "unregister YourEmailAddressHere" to [EMAIL PROTECTED])

Reply via email to