mirror of
https://github.com/postgres/postgres.git
synced 2025-07-26 01:22:12 +03:00
ALTER TABLE SET/DROP NOT NULL, from Christopher Kings-Lynne.
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.40 2002/03/06 20:42:38 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_table.sgml,v 1.41 2002/04/01 04:35:37 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -28,6 +28,8 @@ ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
|
|||||||
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
|
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
|
||||||
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET DEFAULT <replaceable
|
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> { SET DEFAULT <replaceable
|
||||||
class="PARAMETER">value</replaceable> | DROP DEFAULT }
|
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 TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
|
||||||
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
|
ALTER [ COLUMN ] <replaceable class="PARAMETER">column</replaceable> SET STATISTICS <replaceable class="PARAMETER">integer</replaceable>
|
||||||
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
|
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
|
||||||
@ -168,6 +170,9 @@ ALTER TABLE <replaceable class="PARAMETER">table</replaceable>
|
|||||||
allow you to set or remove the default for the column. Note that defaults
|
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
|
only apply to subsequent <command>INSERT</command> commands; they do not
|
||||||
cause rows already in the table to change.
|
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
|
The <literal>ALTER COLUMN SET STATISTICS</literal> form allows you to
|
||||||
set the statistics-gathering target for subsequent
|
set the statistics-gathering target for subsequent
|
||||||
<xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
|
<xref linkend="sql-analyze" endterm="sql-analyze-title"> operations.
|
||||||
@ -279,6 +284,17 @@ ALTER TABLE distributors RENAME TO suppliers;
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</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>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To add a check constraint to a table:
|
To add a check constraint to a table:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.128 2002/03/25 21:24:08 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.129 2002/04/01 04:35:37 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<appendix id="release">
|
<appendix id="release">
|
||||||
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
|
|||||||
worries about funny characters.
|
worries about funny characters.
|
||||||
-->
|
-->
|
||||||
<literallayout><![CDATA[
|
<literallayout><![CDATA[
|
||||||
|
ALTER TABLE ALTER COLUMN SET/DROP NOT NULL
|
||||||
EXPLAIN output comes out as a query result, not a NOTICE message
|
EXPLAIN output comes out as a query result, not a NOTICE message
|
||||||
DOMAINs (types that are constrained versions of base types)
|
DOMAINs (types that are constrained versions of base types)
|
||||||
Access privileges on functions
|
Access privileges on functions
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.169 2002/03/31 06:26:30 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.170 2002/04/01 04:35:38 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PerformAddAttribute() code, like most of the relation
|
* The PerformAddAttribute() code, like most of the relation
|
||||||
@ -403,7 +403,7 @@ AlterTableAddColumn(Oid myrelid,
|
|||||||
|
|
||||||
if (colDef->is_not_null)
|
if (colDef->is_not_null)
|
||||||
elog(ERROR, "Adding NOT NULL columns is not implemented."
|
elog(ERROR, "Adding NOT NULL columns is not implemented."
|
||||||
"\n\tAdd the column, then use ALTER TABLE ADD CONSTRAINT.");
|
"\n\tAdd the column, then use ALTER TABLE ... SET NOT NULL.");
|
||||||
|
|
||||||
pgclass = heap_openr(RelationRelationName, RowExclusiveLock);
|
pgclass = heap_openr(RelationRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
@ -527,18 +527,19 @@ AlterTableAddColumn(Oid myrelid,
|
|||||||
AlterTableCreateToastTable(myrelid, true);
|
AlterTableCreateToastTable(myrelid, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
|
* ALTER TABLE ALTER COLUMN DROP NOT NULL
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
AlterTableAlterColumnDefault(Oid myrelid,
|
AlterTableAlterColumnDropNotNull(Oid myrelid,
|
||||||
bool inh, const char *colName,
|
bool inh, const char *colName)
|
||||||
Node *newDefault)
|
|
||||||
{
|
{
|
||||||
Relation rel;
|
Relation rel;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
int16 attnum;
|
AttrNumber attnum;
|
||||||
|
Relation attr_rel;
|
||||||
|
List *indexoidlist;
|
||||||
|
List *indexoidscan;
|
||||||
|
|
||||||
rel = heap_open(myrelid, AccessExclusiveLock);
|
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||||
|
|
||||||
@ -552,7 +553,288 @@ AlterTableAlterColumnDefault(Oid myrelid,
|
|||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||||
elog(ERROR, "ALTER TABLE: \"%s\" permission denied",
|
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
AlterTableAlterColumnDropNotNull(childrelid,
|
||||||
|
false, colName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -= now do the thing on this relation =- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\"",
|
||||||
|
RelationGetRelationName(rel), 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)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay, actually perform the catalog change
|
||||||
|
*/
|
||||||
|
attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
|
tuple = SearchSysCacheCopy(ATTNAME,
|
||||||
|
ObjectIdGetDatum(myrelid),
|
||||||
|
PointerGetDatum(colName),
|
||||||
|
0, 0);
|
||||||
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
|
||||||
|
RelationGetRelationName(rel), colName);
|
||||||
|
|
||||||
|
((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = FALSE;
|
||||||
|
|
||||||
|
simple_heap_update(attr_rel, &tuple->t_self, tuple);
|
||||||
|
|
||||||
|
/* keep the system catalog indices current */
|
||||||
|
if (RelationGetForm(attr_rel)->relhasindex)
|
||||||
|
{
|
||||||
|
Relation idescs[Num_pg_attr_indices];
|
||||||
|
|
||||||
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
||||||
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, attr_rel, tuple);
|
||||||
|
CatalogCloseIndices(Num_pg_attr_indices, idescs);
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_close(attr_rel, RowExclusiveLock);
|
||||||
|
|
||||||
|
heap_close(rel, NoLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ALTER TABLE ALTER COLUMN SET NOT NULL
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
AlterTableAlterColumnSetNotNull(Oid myrelid,
|
||||||
|
bool inh, const char *colName)
|
||||||
|
{
|
||||||
|
Relation rel;
|
||||||
|
HeapTuple tuple;
|
||||||
|
AttrNumber attnum;
|
||||||
|
Relation attr_rel;
|
||||||
|
HeapScanDesc scan;
|
||||||
|
TupleDesc tupdesc;
|
||||||
|
|
||||||
|
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||||
|
|
||||||
|
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
if (!allowSystemTableMods
|
||||||
|
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||||
|
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
AlterTableAlterColumnSetNotNull(childrelid,
|
||||||
|
false, colName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -= now do the thing on this relation =- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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\"",
|
||||||
|
RelationGetRelationName(rel), 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
|
||||||
|
*/
|
||||||
|
tupdesc = RelationGetDescr(rel);
|
||||||
|
|
||||||
|
scan = heap_beginscan(rel, false, SnapshotNow, 0, NULL);
|
||||||
|
|
||||||
|
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
||||||
|
{
|
||||||
|
Datum d;
|
||||||
|
bool isnull;
|
||||||
|
|
||||||
|
d = heap_getattr(tuple, attnum, tupdesc, &isnull);
|
||||||
|
|
||||||
|
if (isnull)
|
||||||
|
elog(ERROR, "ALTER TABLE: Attribute \"%s\" contains NULL values",
|
||||||
|
colName);
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_endscan(scan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay, actually perform the catalog change
|
||||||
|
*/
|
||||||
|
attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
|
||||||
|
|
||||||
|
tuple = SearchSysCacheCopy(ATTNAME,
|
||||||
|
ObjectIdGetDatum(myrelid),
|
||||||
|
PointerGetDatum(colName),
|
||||||
|
0, 0);
|
||||||
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
|
||||||
|
RelationGetRelationName(rel), colName);
|
||||||
|
|
||||||
|
((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = TRUE;
|
||||||
|
|
||||||
|
simple_heap_update(attr_rel, &tuple->t_self, tuple);
|
||||||
|
|
||||||
|
/* keep the system catalog indices current */
|
||||||
|
if (RelationGetForm(attr_rel)->relhasindex)
|
||||||
|
{
|
||||||
|
Relation idescs[Num_pg_attr_indices];
|
||||||
|
|
||||||
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
||||||
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, attr_rel, tuple);
|
||||||
|
CatalogCloseIndices(Num_pg_attr_indices, idescs);
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_close(attr_rel, RowExclusiveLock);
|
||||||
|
|
||||||
|
heap_close(rel, NoLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
AlterTableAlterColumnDefault(Oid myrelid,
|
||||||
|
bool inh, const char *colName,
|
||||||
|
Node *newDefault)
|
||||||
|
{
|
||||||
|
Relation rel;
|
||||||
|
HeapTuple tuple;
|
||||||
|
AttrNumber attnum;
|
||||||
|
|
||||||
|
rel = heap_open(myrelid, AccessExclusiveLock);
|
||||||
|
|
||||||
|
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
if (!allowSystemTableMods
|
||||||
|
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
|
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||||
|
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -620,44 +902,36 @@ AlterTableAlterColumnDefault(Oid myrelid,
|
|||||||
{
|
{
|
||||||
/* DROP DEFAULT */
|
/* DROP DEFAULT */
|
||||||
Relation attr_rel;
|
Relation attr_rel;
|
||||||
ScanKeyData scankeys[3];
|
|
||||||
HeapScanDesc scan;
|
|
||||||
|
|
||||||
|
/* Fix the pg_attribute row */
|
||||||
attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);
|
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_atthasdef, F_BOOLEQ,
|
|
||||||
BoolGetDatum(true));
|
|
||||||
|
|
||||||
scan = heap_beginscan(attr_rel, false, SnapshotNow, 3, scankeys);
|
tuple = SearchSysCacheCopy(ATTNAME,
|
||||||
AssertState(scan != NULL);
|
ObjectIdGetDatum(myrelid),
|
||||||
|
PointerGetDatum(colName),
|
||||||
|
0, 0);
|
||||||
|
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */
|
||||||
|
elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
|
||||||
|
RelationGetRelationName(rel), colName);
|
||||||
|
|
||||||
if (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
|
((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = FALSE;
|
||||||
|
|
||||||
|
simple_heap_update(attr_rel, &tuple->t_self, tuple);
|
||||||
|
|
||||||
|
/* keep the system catalog indices current */
|
||||||
|
if (RelationGetForm(attr_rel)->relhasindex)
|
||||||
{
|
{
|
||||||
HeapTuple newtuple;
|
Relation idescs[Num_pg_attr_indices];
|
||||||
Relation irelations[Num_pg_attr_indices];
|
|
||||||
|
|
||||||
/* update to false */
|
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
|
||||||
newtuple = heap_copytuple(tuple);
|
CatalogIndexInsert(idescs, Num_pg_attr_indices, attr_rel, tuple);
|
||||||
((Form_pg_attribute) GETSTRUCT(newtuple))->atthasdef = FALSE;
|
CatalogCloseIndices(Num_pg_attr_indices, idescs);
|
||||||
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);
|
|
||||||
|
|
||||||
/* get rid of actual default definition */
|
|
||||||
drop_default(myrelid, attnum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_endscan(scan);
|
heap_close(attr_rel, RowExclusiveLock);
|
||||||
heap_close(attr_rel, NoLock);
|
|
||||||
|
/* get rid of actual default definition in pg_attrdef */
|
||||||
|
drop_default(myrelid, attnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
@ -722,7 +996,7 @@ AlterTableAlterColumnFlags(Oid myrelid,
|
|||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||||
elog(ERROR, "ALTER TABLE: \"%s\" permission denied",
|
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1011,7 +1285,7 @@ AlterTableDropColumn(Oid myrelid,
|
|||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
if (!allowSystemTableMods
|
if (!allowSystemTableMods
|
||||||
&& IsSystemRelationName(RelationGetRelationName(rel))
|
&& IsSystemRelationName(RelationGetRelationName(rel)))
|
||||||
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
@ -1022,7 +1296,8 @@ AlterTableDropColumn(Oid myrelid,
|
|||||||
* normally, only the owner of a class can change its schema.
|
* normally, only the owner of a class can change its schema.
|
||||||
*/
|
*/
|
||||||
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
if (!pg_class_ownercheck(myrelid, GetUserId()))
|
||||||
elog(ERROR, "ALTER TABLE: permission denied");
|
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
heap_close(rel, NoLock); /* close rel but keep lock! */
|
heap_close(rel, NoLock); /* close rel but keep lock! */
|
||||||
|
|
||||||
@ -1670,7 +1945,8 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
|
|||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
if (!pg_class_ownercheck(relOid, GetUserId()))
|
if (!pg_class_ownercheck(relOid, GetUserId()))
|
||||||
elog(ERROR, "ALTER TABLE: permission denied");
|
elog(ERROR, "ALTER TABLE: \"%s\": permission denied",
|
||||||
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lock the pg_class tuple for update (is that really needed?)
|
* lock the pg_class tuple for update (is that really needed?)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.298 2002/04/01 03:34:25 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.299 2002/04/01 04:35:38 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -1122,6 +1122,24 @@ AlterTableStmt:
|
|||||||
n->def = $7;
|
n->def = $7;
|
||||||
$$ = (Node *)n;
|
$$ = (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> ALTER [COLUMN] <colname> SET STATISTICS <Iconst> */
|
||||||
| ALTER TABLE relation_expr ALTER opt_column ColId SET STATISTICS Iconst
|
| ALTER TABLE relation_expr ALTER opt_column ColId SET STATISTICS Iconst
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.144 2002/03/31 07:49:30 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.145 2002/04/01 04:35:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -437,6 +437,16 @@ ProcessUtility(Node *parsetree,
|
|||||||
stmt->name,
|
stmt->name,
|
||||||
stmt->def);
|
stmt->def);
|
||||||
break;
|
break;
|
||||||
|
case 'N': /* ALTER COLUMN DROP NOT NULL */
|
||||||
|
AlterTableAlterColumnDropNotNull(RangeVarGetRelid(stmt->relation, false),
|
||||||
|
interpretInhOption(stmt->relation->inhOpt),
|
||||||
|
stmt->name);
|
||||||
|
break;
|
||||||
|
case 'O': /* ALTER COLUMN SET NOT NULL */
|
||||||
|
AlterTableAlterColumnSetNotNull(RangeVarGetRelid(stmt->relation, false),
|
||||||
|
interpretInhOption(stmt->relation->inhOpt),
|
||||||
|
stmt->name);
|
||||||
|
break;
|
||||||
case 'S': /* ALTER COLUMN STATISTICS */
|
case 'S': /* ALTER COLUMN STATISTICS */
|
||||||
case 'M': /* ALTER COLUMN STORAGE */
|
case 'M': /* ALTER COLUMN STORAGE */
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: command.h,v 1.36 2002/03/29 19:06:21 tgl Exp $
|
* $Id: command.h,v 1.37 2002/04/01 04:35:39 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -45,6 +45,12 @@ extern void AlterTableAddColumn(Oid myrelid, bool inherits, ColumnDef *colDef);
|
|||||||
extern void AlterTableAlterColumnDefault(Oid myrelid, bool inh,
|
extern void AlterTableAlterColumnDefault(Oid myrelid, bool inh,
|
||||||
const char *colName, Node *newDefault);
|
const char *colName, Node *newDefault);
|
||||||
|
|
||||||
|
extern void AlterTableAlterColumnDropNotNull(Oid myrelid,
|
||||||
|
bool inh, const char *colName);
|
||||||
|
|
||||||
|
extern void AlterTableAlterColumnSetNotNull(Oid myrelid,
|
||||||
|
bool inh, const char *colName);
|
||||||
|
|
||||||
extern void AlterTableAlterColumnFlags(Oid myrelid,
|
extern void AlterTableAlterColumnFlags(Oid myrelid,
|
||||||
bool inh, const char *colName,
|
bool inh, const char *colName,
|
||||||
Node *flagValue, const char *flagType);
|
Node *flagValue, const char *flagType);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.166 2002/03/29 19:06:23 tgl Exp $
|
* $Id: parsenodes.h,v 1.167 2002/04/01 04:35:40 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -728,6 +728,8 @@ typedef struct AlterTableStmt
|
|||||||
char subtype; /*------------
|
char subtype; /*------------
|
||||||
* A = add column
|
* A = add column
|
||||||
* T = alter column default
|
* T = alter column default
|
||||||
|
* N = alter column drop not null
|
||||||
|
* O = alter column set not null
|
||||||
* S = alter column statistics
|
* S = alter column statistics
|
||||||
* M = alter column storage
|
* M = alter column storage
|
||||||
* D = drop column
|
* D = drop column
|
||||||
|
@ -578,3 +578,74 @@ ERROR: Cannot insert a duplicate key into unique index atacc1_pkey
|
|||||||
insert into atacc1 (test2, test) values (1, NULL);
|
insert into atacc1 (test2, test) values (1, NULL);
|
||||||
ERROR: ExecAppend: Fail to add null value in not null attribute test
|
ERROR: ExecAppend: Fail to add null value in not null attribute test
|
||||||
drop table atacc1;
|
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;
|
||||||
|
@ -452,3 +452,64 @@ insert into atacc1 (test2, test) values (3, 3);
|
|||||||
insert into atacc1 (test2, test) values (2, 3);
|
insert into atacc1 (test2, test) values (2, 3);
|
||||||
insert into atacc1 (test2, test) values (1, NULL);
|
insert into atacc1 (test2, test) values (1, NULL);
|
||||||
drop table atacc1;
|
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;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user