notnull_constraint.patch
application/octet-stream
Filename: notnull_constraint.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/catalog/heap.c | 0 | 0 |
| src/backend/commands/tablecmds.c | 0 | 0 |
| src/backend/parser/parse_utilcmd.c | 0 | 0 |
| src/backend/port/pg_latch.c | 0 | 0 |
| src/backend/utils/adt/ruleutils.c | 0 | 0 |
| src/include/catalog/heap.h | 0 | 0 |
| src/include/catalog/pg_constraint.h | 0 | 0 |
| src/include/nodes/parsenodes.h | 0 | 0 |
| src/test/regress/expected/alter_table.out | 0 | 0 |
| src/test/regress/expected/cluster.out | 0 | 0 |
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 9403dc1..5b82dd8 100644
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
*************** StoreAttrDefault(Relation rel, AttrNumbe
*** 1714,1719 ****
--- 1714,1759 ----
}
/*
+ * Stores a NOT NULL constraint of a column into pg_constraint.
+ */
+ void
+ StoreColumnNotNullConstraint(Relation rel, CookedConstraint *cooked)
+ {
+
+ /*
+ * Store the constraint. Reflect conislocal and coninhcount to
+ * match the same values as the attached column.
+ */
+ CreateConstraintEntry(cooked->name,
+ RelationGetNamespace(rel),
+ CONSTRAINT_NOTNULL,
+ false,
+ false,
+ RelationGetRelid(rel),
+ &(cooked->attnum),
+ 1,
+ InvalidOid,
+ InvalidOid,
+ InvalidOid,
+ NULL,
+ InvalidOid,
+ InvalidOid,
+ InvalidOid,
+ 0,
+ ' ',
+ ' ',
+ ' ',
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ cooked->is_local,
+ cooked->inhcount
+ );
+
+ }
+
+ /*
* Store a check-constraint expression for the given relation.
*
* Caller is responsible for updating the count of constraints
*************** StoreConstraints(Relation rel, List *coo
*** 1837,1842 ****
--- 1877,1885 ----
switch (con->contype)
{
+ case CONSTR_NOTNULL:
+ StoreColumnNotNullConstraint(rel, con);
+ break;
case CONSTR_DEFAULT:
StoreAttrDefault(rel, con->attnum, con->expr);
break;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1e5ac13..af87b58 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** typedef struct NewColumnValue
*** 175,180 ****
--- 175,192 ----
} NewColumnValue;
/*
+ * Struct describing the constraint information
+ * to de-inherit. Currently CHECK and NOT NULL constraints
+ * are carried by ATExecDropInherit() within these struct.
+ */
+ typedef struct DeinheritConstraintInfo
+ {
+ char contype; /* constraint type */
+ AttrNumber attnum; /* if NOT NULL constraint, the attnum */
+ char *conname; /* if CHECK constraint, the constraint name */
+ } DeinheritConstraintInfo;
+
+ /*
* Error-reporting support for RemoveRelations
*/
struct dropmsgstrings
*************** static List *MergeAttributes(List *schem
*** 227,234 ****
List **supOids, List **supconstr, int *supOidCount);
static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
static bool change_varattnos_walker(Node *node, const AttrNumber *newattno);
! static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
! static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
int16 seqNumber, Relation inhRelation);
--- 239,248 ----
List **supOids, List **supconstr, int *supOidCount);
static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
static bool change_varattnos_walker(Node *node, const AttrNumber *newattno);
! static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel,
! List **child_attnums);
! static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel,
! List *child_attnums);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static void StoreCatalogInheritance1(Oid relationId, Oid parentOid,
int16 seqNumber, Relation inhRelation);
*************** static void ATExecAddColumn(AlteredTable
*** 275,282 ****
ColumnDef *colDef, bool isOid, LOCKMODE lockmode);
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
! AlterTableCmd *cmd, LOCKMODE lockmode);
! static void ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode);
static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
const char *colName, LOCKMODE lockmode);
static void ATExecColumnDefault(Relation rel, const char *colName,
--- 289,297 ----
ColumnDef *colDef, bool isOid, LOCKMODE lockmode);
static void add_column_datatype_dependency(Oid relid, int32 attnum, Oid typid);
static void ATPrepAddOids(List **wqueue, Relation rel, bool recurse,
! AlterTableCmd *cmd, LOCKMODE lockmode);
! static void ATExecDropNotNull(Relation rel, const char *colName, DropBehavior behavior,
! bool recurse, bool recursing, LOCKMODE lockmode);
static void ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
const char *colName, LOCKMODE lockmode);
static void ATExecColumnDefault(Relation rel, const char *colName,
*************** static void ATExecDropInherit(Relation r
*** 335,341 ****
static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
ForkNumber forkNum, bool istemp);
static const char *storage_name(char c);
!
/* ----------------------------------------------------------------
* DefineRelation
--- 350,363 ----
static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
ForkNumber forkNum, bool istemp);
static const char *storage_name(char c);
! static bool ATExecDropNotNullInternal(Relation rel, HeapTuple constrtup,
! DropBehavior behavior,
! bool recurse, bool recursing);
! static bool
! CheckNotNullOnAttributeName(Relation rel, const char *colname,
! AttrNumber *attnum);
! static void
! DropNotNullOnAttributeNum(Relation rel, AttrNumber attnum, bool lock);
/* ----------------------------------------------------------------
* DefineRelation
*************** DefineRelation(CreateStmt *stmt, char re
*** 507,512 ****
--- 529,555 ----
attnum++;
+ if (colDef->is_not_null) {
+ /*
+ * Adjust NOT NULL constraint of this column
+ * to hold new attnum and inheritance information
+ *
+ * XXX: Currently the constraint is cheated into cookedDefaults
+ * list, maybe we need to invent a different machinerie/naming.
+ */
+ CookedConstraint *cooked;
+
+ cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
+ cooked->contype = CONSTR_NOTNULL;
+ cooked->name = ChooseConstraintName(relname, NameStr(descriptor->attrs[attnum - 1]->attname),
+ "not_null", namespaceId, NIL);
+ cooked->attnum = attnum;
+ cooked->expr = NULL;
+ cooked->is_local = colDef->is_local;
+ cooked->inhcount = colDef->inhcount;
+ cookedDefaults = lappend(cookedDefaults, cooked);
+ }
+
if (colDef->raw_default != NULL)
{
RawColumnDefault *rawEnt;
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2666,2672 ****
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
ATSimplePermissions(rel, false);
! ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
/* No command-specific prep needed */
pass = AT_PASS_DROP;
break;
--- 2709,2718 ----
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
ATSimplePermissions(rel, false);
!
! if (recurse)
! cmd->subtype = AT_DropNotNullRecurse;
!
/* No command-specific prep needed */
pass = AT_PASS_DROP;
break;
*************** ATExecCmd(List **wqueue, AlteredTableInf
*** 2896,2902 ****
ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
! ATExecDropNotNull(rel, cmd->name, lockmode);
break;
case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
ATExecSetNotNull(tab, rel, cmd->name, lockmode);
--- 2942,2953 ----
ATExecColumnDefault(rel, cmd->name, cmd->def, lockmode);
break;
case AT_DropNotNull: /* ALTER COLUMN DROP NOT NULL */
! ATExecDropNotNull(rel, cmd->name, cmd->behavior,
! false, false, lockmode);
! break;
! case AT_DropNotNullRecurse: /* ALTER COLUMN DROP NOT NULL with recursion */
! ATExecDropNotNull(rel, cmd->name, cmd->behavior,
! true, false, lockmode);
break;
case AT_SetNotNull: /* ALTER COLUMN SET NOT NULL */
ATExecSetNotNull(tab, rel, cmd->name, lockmode);
*************** ATPrepAddOids(List **wqueue, Relation re
*** 4111,4157 ****
* ALTER TABLE ALTER COLUMN DROP NOT NULL
*/
static void
! ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
{
! HeapTuple tuple;
AttrNumber attnum;
! Relation attr_rel;
! List *indexoidlist;
! ListCell *indexoidscan;
/*
! * lookup the attribute
*/
! attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
! tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
! if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
! colName, RelationGetRelationName(rel))));
! attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
/* Prevent them from altering a system attribute */
! if (attnum <= 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("cannot alter system column \"%s\"",
! colName)));
/*
! * Check that the attribute is not in a primary key
*/
/* Loop over all indexes on the relation */
indexoidlist = RelationGetIndexList(rel);
!
foreach(indexoidscan, indexoidlist)
{
! Oid indexoid = lfirst_oid(indexoidscan);
! HeapTuple indexTuple;
Form_pg_index indexStruct;
int i;
--- 4162,4507 ----
* ALTER TABLE ALTER COLUMN DROP NOT NULL
*/
static void
! ATExecDropNotNull(Relation rel, const char *colName, DropBehavior behavior,
! bool recurse, bool recursing, LOCKMODE lockmode)
{
! List *children;
! ListCell *child;
! HeapTuple constr_tuple;
AttrNumber attnum;
! Relation constr_rel;
! SysScanDesc scan;
! ScanKeyData key;
! bool found;
!
! if (recursing)
! ATSimplePermissions(rel, false);
/*
! * Lookup the attribute. This also checks for a dropped column
! * or any attempts to alter a system column. Returns false in case
! * no further work needs to be done (e.g. no NOT NULL present).
*/
! if (!CheckNotNullOnAttributeName(rel, colName, &attnum))
! return;
! /*
! * Scan through our constraint records, looking for the matching
! * NOT NULL constraint.
! */
! constr_rel = heap_open(ConstraintRelationId, RowExclusiveLock);
! ScanKeyInit(&key,
! Anum_pg_constraint_conrelid,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(RelationGetRelid(rel)));
! scan = systable_beginscan(constr_rel, ConstraintRelidIndexId,
! true, SnapshotNow, 1, &key);
!
! while(HeapTupleIsValid(constr_tuple = systable_getnext(scan)))
! {
! Form_pg_constraint constrStruct;
! Datum arrayp;
! Datum *keyvals;
! int nelems;
! bool isnull;
! constrStruct = (Form_pg_constraint) GETSTRUCT(constr_tuple);
!
! if (constrStruct->contype != CONSTRAINT_NOTNULL)
! continue;
!
! /*
! * Check wether this constraint is attached to the given column.
! * ATExecSetNotNull() ensures that only one NOT NULL constraint tuple
! * lives per attribute.
! */
! arrayp = SysCacheGetAttr(CONSTROID, constr_tuple, Anum_pg_constraint_conkey, &isnull);
!
! /* should not happen */
! Assert(!isnull);
!
! deconstruct_array(DatumGetArrayTypeP(arrayp), INT2OID, 2, true,
! 's', &keyvals, NULL, &nelems);
!
! /* Is this NOT NULL constraint attached to the current tuple? */
! if (DatumGetInt16(keyvals[0]) != attnum)
! continue;
!
! /*
! * Check if the attribute is inherited from another relation or
! * part of a primary key.
! * If true, error out, otherwise perform the deletion of the constraint.
! *
! * Note: ATExecDropNotNullInternal() performs a CCI, if required.
! */
! if ((found = ATExecDropNotNullInternal(rel,
! constr_tuple,
! behavior,
! recurse, recursing)))
! {
! /*
! * Okay, actually remove the NOT NULL from pg_attribute.
! * CheckNotNullOnAttributeName() already holds a lock on pg_attribute, so
! * override an additional lock here.
! */
! DropNotNullOnAttributeNum(rel, attnum, false);
! break;
! }
! }
!
! systable_endscan(scan);
!
! if (found)
! {
! /*
! * Propagate to children as appropriate.
! */
! children = find_inheritance_children(RelationGetRelid(rel),
! AccessExclusiveLock);
! }
! else
! {
! ereport(ERROR,
! (errcode(ERRCODE_UNDEFINED_OBJECT),
! errmsg("column \"%s\" of relation \"%s\" has no NOT NULL constraint",
! colName,
! RelationGetRelationName(rel))));
! }
!
! foreach(child, children)
! {
! Oid childrelid = lfirst_oid(child);
! Relation childrel;
!
! childrel = heap_open(childrelid, NoLock);
! CheckTableNotInUse(childrel, "ALTER TABLE");
!
! ScanKeyInit(&key,
! Anum_pg_constraint_conrelid,
! BTEqualStrategyNumber, F_OIDEQ,
! ObjectIdGetDatum(childrelid));
! scan = systable_beginscan(constr_rel, ConstraintRelidIndexId,
! true, SnapshotNow, 1, &key);
!
! while (HeapTupleIsValid(constr_tuple = systable_getnext(scan)))
! {
! HeapTuple copy_tuple;
! Form_pg_constraint constrStruct;
! Datum arrayp;
! Datum *keyvals;
! int nelems;
! bool isnull;
!
! constrStruct = (Form_pg_constraint) GETSTRUCT(constr_tuple);
!
! if (constrStruct->contype != CONSTRAINT_NOTNULL)
! continue;
!
! /*
! * Check wether this constraint is attached to the given column.
! * ATExecSetNotNull() ensures that only one NOT NULL constraint tuple
! * lives per attribute.
! */
! arrayp = SysCacheGetAttr(CONSTROID, constr_tuple, Anum_pg_constraint_conkey, &isnull);
!
! /* should not happen */
! Assert(!isnull);
!
! deconstruct_array(DatumGetArrayTypeP(arrayp), INT2OID, 2, true,
! 's', &keyvals, NULL, &nelems);
!
! /* Is this NOT NULL constraint attached to the current tuple? */
! if (DatumGetInt16(keyvals[0]) != attnum)
! continue;
!
! found = true;
!
! if (constrStruct->coninhcount <= 0) /* shouldn't happen */
! elog(ERROR, "relation %u has non-inherited NOT NULL constraint \"%s\"",
! childrelid, NameStr(constrStruct->conname));
!
! copy_tuple = heap_copytuple(constr_tuple);
! constrStruct = (Form_pg_constraint) GETSTRUCT(copy_tuple);
!
! if (recurse)
! {
! /*
! * If the child constraint has other definition sources, just
! * decrement its inheritance count; if not, recurse to delete
! * it.
! */
! if (constrStruct->coninhcount == 1 && !constrStruct->conislocal)
! {
! /* Time to delete this child constraint, too */
! ATExecDropNotNull(childrel, colName, behavior,
! true, true, lockmode);
! }
! else
! {
! /* Child constraint must survive my deletion */
! constrStruct->coninhcount--;
! simple_heap_update(constr_rel, ©_tuple->t_self, copy_tuple);
! CatalogUpdateIndexes(constr_rel, copy_tuple);
!
! /* Make update visible */
! CommandCounterIncrement();
! }
! }
! else
! {
! /*
! * If we were told to drop ONLY in this table (no recursion),
! * we need to mark the inheritors' constraints as locally
! * defined rather than inherited.
! */
! constrStruct->coninhcount--;
! constrStruct->conislocal = true;
!
! simple_heap_update(constr_rel, ©_tuple->t_self, copy_tuple);
! CatalogUpdateIndexes(constr_rel, copy_tuple);
!
! /* Make update visible */
! CommandCounterIncrement();
! }
!
! heap_freetuple(copy_tuple);
!
! }
!
! systable_endscan(scan);
! heap_close(childrel, NoLock);
!
! }
!
! heap_close(constr_rel, NoLock);
!
! }
!
! /*
! * Does the leg work on dropping a NOT NULL constraint
! * identified by the given constrtup tuple.
! *
! * Note: The caller is responsible to pass a valid
! * CONSTRAINT_NOTNULL tuple.
! */
! static bool
! ATExecDropNotNullInternal(Relation rel, HeapTuple constrtup,
! DropBehavior behavior,
! bool recurse, bool recursing)
! {
! bool found;
! Form_pg_constraint constrStruct;
! ObjectAddress conobj;
!
! found = false;
!
! if (HeapTupleIsValid(constrtup))
! {
!
! constrStruct = (Form_pg_constraint) GETSTRUCT(constrtup);
!
! /*
! * Be paranoid, caller is responsible to pass a valid HeapTuple.
! */
! Assert(constrStruct->contype == CONSTRAINT_NOTNULL);
!
! /* It is okay to drop this constraint when recursing */
! if ((constrStruct->coninhcount > 0) && (!recursing))
! {
! ereport(ERROR,
! (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
! errmsg("cannot drop inherited NOT NULL constraint \"%s\", relation \"%s\"",
! NameStr(constrStruct->conname), RelationGetRelationName(rel))));
! }
!
! /*
! * Time to drop the constraint now.
! */
! conobj.classId = ConstraintRelationId;
! conobj.objectId = HeapTupleGetOid(constrtup);
! conobj.objectSubId = 0;
!
! performDeletion(&conobj, behavior);
!
! /*
! * Make sure changes are visible
! */
! CommandCounterIncrement();
! found = true;
!
! }
!
! return found;
! }
!
! /*
! * Checks wether the given attribute name has a NOT NULL constraint attached
! * which can be dropped.
! *
! * Any attempts to drop a NOT NULL constraint on a system
! * column or non-existing column will throw an error. Returns true
! * in case the caller is allowed to proceed, false if no NOT NULL flag
! * was set on the attribute.
! */
! static bool
! CheckNotNullOnAttributeName(Relation rel, const char *colname, AttrNumber *attnum)
! {
! Relation attr_rel;
! HeapTuple attr_tuple;
! Form_pg_attribute attr_struct;
! bool has_not_null;
! List *indexoidlist;
! ListCell *indexoidscan;
!
! has_not_null = false;
!
! attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
! attr_tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colname);
!
! if (!HeapTupleIsValid(attr_tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
! colname,
! RelationGetRelationName(rel))));
! /* attribute exists */
! attr_struct = (Form_pg_attribute) GETSTRUCT(attr_tuple);
/* Prevent them from altering a system attribute */
! if (attr_struct->attnum <= 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("cannot alter system column \"%s\" of relation \"%s\"",
! colname,
! RelationGetRelationName(rel))));
/*
! * Check for dropped attributes
*/
+ if (attr_struct->attisdropped)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("attempt to drop NOT NULL constraint on dropped column \"%s\" of relation \"%s\"",
+ colname,
+ RelationGetRelationName(rel))));
+ }
+ if (attnum)
+ *attnum = attr_struct->attnum;
+
+ /*
+ * Check that the attribute is not in a primary key
+ */
+
/* Loop over all indexes on the relation */
indexoidlist = RelationGetIndexList(rel);
!
foreach(indexoidscan, indexoidlist)
{
! Oid indexoid = lfirst_oid(indexoidscan);
! HeapTuple indexTuple;
Form_pg_index indexStruct;
int i;
*************** ATExecDropNotNull(Relation rel, const ch
*** 4159,4165 ****
if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "cache lookup failed for index %u", indexoid);
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
!
/* If the index is not a primary key, skip the check */
if (indexStruct->indisprimary)
{
--- 4509,4515 ----
if (!HeapTupleIsValid(indexTuple))
elog(ERROR, "cache lookup failed for index %u", indexoid);
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
!
/* If the index is not a primary key, skip the check */
if (indexStruct->indisprimary)
{
*************** ATExecDropNotNull(Relation rel, const ch
*** 4169,4201 ****
*/
for (i = 0; i < indexStruct->indnatts; i++)
{
! if (indexStruct->indkey.values[i] == attnum)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" is in a primary key",
! colName)));
}
}
!
ReleaseSysCache(indexTuple);
}
! list_free(indexoidlist);
!
! /*
! * Okay, actually perform the catalog change ... if needed
*/
! if (((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
! {
! ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = FALSE;
! simple_heap_update(attr_rel, &tuple->t_self, tuple);
! /* keep the system catalog indexes current */
! CatalogUpdateIndexes(attr_rel, tuple);
! }
- heap_close(attr_rel, RowExclusiveLock);
}
/*
--- 4519,4581 ----
*/
for (i = 0; i < indexStruct->indnatts; i++)
{
! if (indexStruct->indkey.values[i] == attr_struct->attnum)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("column \"%s\" is in a primary key",
! colname)));
}
}
!
ReleaseSysCache(indexTuple);
}
! /*
! * In case no NOT NULL constraint was set on the
! * column, give up and tell the caller we haven't done
! * anything.
*/
! has_not_null = ((!attr_struct->attnotnull) ? false : true);
! heap_freetuple(attr_tuple);
! heap_close(attr_rel, NoLock);
! return has_not_null;
! }
! /*
! * Drops a NOT NULL constraint from the given attribute number of the
! * specified relation.
! */
! static void
! DropNotNullOnAttributeNum(Relation rel, AttrNumber attnum, bool lock)
! {
! Relation attr_rel;
! HeapTuple attr_tuple;
! Form_pg_attribute attr_struct;
!
! if (lock)
! attr_rel = heap_open(AttributeRelationId, RowExclusiveLock);
! else
! attr_rel = heap_open(AttributeRelationId, NoLock);
!
! attr_tuple = SearchSysCacheCopy(ATTNUM,
! ObjectIdGetDatum(RelationGetRelid(rel)),
! Int16GetDatum(attnum),
! 0, 0);
!
! attr_struct = (Form_pg_attribute) GETSTRUCT(attr_tuple);
!
! /* not expected, so be paranoid */
! Assert(attr_struct->attnotnull);
!
! ((Form_pg_attribute) GETSTRUCT(attr_tuple))->attnotnull = FALSE;
! simple_heap_update(attr_rel, &attr_tuple->t_self, attr_tuple);
!
! /* keep the system catalog indexes current */
! CatalogUpdateIndexes(attr_rel, attr_tuple);
!
! heap_close(attr_rel, NoLock);
}
/*
*************** ATExecSetNotNull(AlteredTableInfo *tab,
*** 4228,4241 ****
if (attnum <= 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("cannot alter system column \"%s\"",
! colName)));
/*
* Okay, actually perform the catalog change ... if needed
*/
if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
{
((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = TRUE;
simple_heap_update(attr_rel, &tuple->t_self, tuple);
--- 4608,4649 ----
if (attnum <= 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! errmsg("cannot alter system column \"%s\" of relation \"%s\"",
! colName, RelationGetRelationName(rel))));
/*
* Okay, actually perform the catalog change ... if needed
*/
if (!((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull)
{
+ /*
+ * Setting attnotnull to TRUE requires to create a
+ * constraint tuple in pg_constraint as well. We do this
+ * to record wether this constraint was added locally or
+ * inherited by some other attribute. We also record the
+ * attribute number to determine which column this
+ * constraint belongs to.
+ */
+ CookedConstraint *cooked = palloc(sizeof(CookedConstraint));
+ cooked->contype = CONSTR_NOTNULL;
+ cooked->expr = NULL;
+ cooked->name = ChooseConstraintName(RelationGetRelationName(rel),
+ NameStr(((Form_pg_attribute) GETSTRUCT(tuple))->attname),
+ "not_null", RelationGetNamespace(rel), NIL);
+ cooked->attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
+ cooked->is_local = ((Form_pg_attribute) GETSTRUCT(tuple))->attislocal;
+ cooked->inhcount = ((Form_pg_attribute) GETSTRUCT(tuple))->attinhcount;
+ StoreColumnNotNullConstraint(rel, cooked);
+
+ /*
+ * Make changes visible
+ */
+ CommandCounterIncrement();
+
+ /*
+ * Finally record in pg_attribute that there is a NOT NULL
+ * constraint.
+ */
((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull = TRUE;
simple_heap_update(attr_rel, &tuple->t_self, tuple);
*************** ATExecDropConstraint(Relation rel, const
*** 5821,5826 ****
--- 6229,6238 ----
con = (Form_pg_constraint) GETSTRUCT(tuple);
+ /* NOT NULL is handled by ALTER TABLE ... DROP/SET NOT NULL */
+ if (con->contype == CONSTRAINT_NOTNULL)
+ continue;
+
if (strcmp(NameStr(con->conname), constrName) != 0)
continue;
*************** ATExecDropConstraint(Relation rel, const
*** 5831,5837 ****
errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
constrName, RelationGetRelationName(rel))));
! /* Right now only CHECK constraints can be inherited */
if (con->contype == CONSTRAINT_CHECK)
is_check_constraint = true;
--- 6243,6251 ----
errmsg("cannot drop inherited constraint \"%s\" of relation \"%s\"",
constrName, RelationGetRelationName(rel))));
! /* This is a CHECK constraint, remember that we found one
! * and proceed to drop it
! */
if (con->contype == CONSTRAINT_CHECK)
is_check_constraint = true;
*************** ATExecDropConstraint(Relation rel, const
*** 5902,5908 ****
con = (Form_pg_constraint) GETSTRUCT(tuple);
! /* Right now only CHECK constraints can be inherited */
if (con->contype != CONSTRAINT_CHECK)
continue;
--- 6316,6325 ----
con = (Form_pg_constraint) GETSTRUCT(tuple);
! /* Besides CHECK constraint we support inheritance of
! * NOT NULL constraints, too. Ignore them here, since they
! * are handled by ALTER TABLE...DROP/SET NOT NULL
! */
if (con->contype != CONSTRAINT_CHECK)
continue;
*************** ATPostAlterTypeParse(char *cmd, List **w
*** 6595,6600 ****
--- 7012,7018 ----
tab->subcmds[AT_PASS_OLD_INDEX] =
lappend(tab->subcmds[AT_PASS_OLD_INDEX], cmd);
break;
+ case AT_SetNotNull:
case AT_AddConstraint:
tab->subcmds[AT_PASS_OLD_CONSTR] =
lappend(tab->subcmds[AT_PASS_OLD_CONSTR], cmd);
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7356,7361 ****
--- 7774,7780 ----
HeapTuple inheritsTuple;
int32 inhseqno;
List *children;
+ List *child_attnums;
/*
* AccessShareLock on the parent is what's obtained during normal CREATE
*************** ATExecAddInherit(Relation child_rel, Ran
*** 7442,7451 ****
RelationGetRelationName(parent_rel))));
/* Match up the columns and bump attinhcount as needed */
! MergeAttributesIntoExisting(child_rel, parent_rel);
/* Match up the constraints and bump coninhcount as needed */
! MergeConstraintsIntoExisting(child_rel, parent_rel);
/*
* OK, it looks valid. Make the catalog entries that show inheritance.
--- 7861,7871 ----
RelationGetRelationName(parent_rel))));
/* Match up the columns and bump attinhcount as needed */
! child_attnums = NIL;
! MergeAttributesIntoExisting(child_rel, parent_rel, &child_attnums);
/* Match up the constraints and bump coninhcount as needed */
! MergeConstraintsIntoExisting(child_rel, parent_rel, child_attnums);
/*
* OK, it looks valid. Make the catalog entries that show inheritance.
*************** constraints_equivalent(HeapTuple a, Heap
*** 7521,7527 ****
* the child must be as well. Defaults are not compared, however.
*/
static void
! MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
{
Relation attrrel;
AttrNumber parent_attno;
--- 7941,7948 ----
* the child must be as well. Defaults are not compared, however.
*/
static void
! MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel,
! List **attnums_list)
{
Relation attrrel;
AttrNumber parent_attno;
*************** MergeAttributesIntoExisting(Relation chi
*** 7568,7573 ****
--- 7989,7999 ----
attributeName)));
/*
+ * Record the child's inherited attnum in attnums_list.
+ */
+ *attnums_list = lappend_int(*attnums_list, childatt->attnum);
+
+ /*
* OK, bump the child column's inheritance count. (If we fail
* later on, this change will just roll back.)
*/
*************** MergeAttributesIntoExisting(Relation chi
*** 7606,7612 ****
* a problem though. Even 100 constraints ought not be the end of the world.
*/
static void
! MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel)
{
Relation catalog_relation;
TupleDesc tuple_desc;
--- 8032,8039 ----
* a problem though. Even 100 constraints ought not be the end of the world.
*/
static void
! MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel,
! List *child_attnums)
{
Relation catalog_relation;
TupleDesc tuple_desc;
*************** MergeConstraintsIntoExisting(Relation ch
*** 7633,7639 ****
HeapTuple child_tuple;
bool found = false;
! if (parent_con->contype != CONSTRAINT_CHECK)
continue;
/* Search for a child constraint matching this one */
--- 8060,8067 ----
HeapTuple child_tuple;
bool found = false;
! if (parent_con->contype != CONSTRAINT_CHECK
! && parent_con->contype != CONSTRAINT_NOTNULL)
continue;
/* Search for a child constraint matching this one */
*************** MergeConstraintsIntoExisting(Relation ch
*** 7649,7667 ****
Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
HeapTuple child_copy;
! if (child_con->contype != CONSTRAINT_CHECK)
! continue;
! if (strcmp(NameStr(parent_con->conname),
! NameStr(child_con->conname)) != 0)
! continue;
! if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
! ereport(ERROR,
! (errcode(ERRCODE_DATATYPE_MISMATCH),
! errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
! RelationGetRelationName(child_rel),
! NameStr(parent_con->conname))));
/*
* OK, bump the child constraint's inheritance count. (If we fail
--- 8077,8123 ----
Form_pg_constraint child_con = (Form_pg_constraint) GETSTRUCT(child_tuple);
HeapTuple child_copy;
! switch(child_con->contype)
! {
! case CONSTRAINT_CHECK:
! {
! if (strcmp(NameStr(parent_con->conname),
! NameStr(child_con->conname)) != 0)
! continue;
!
! if (!constraints_equivalent(parent_tuple, child_tuple, tuple_desc))
! ereport(ERROR,
! (errcode(ERRCODE_DATATYPE_MISMATCH),
! errmsg("child table \"%s\" has different definition for check constraint \"%s\"",
! RelationGetRelationName(child_rel),
! NameStr(parent_con->conname))));
! break;
! }
! case CONSTRAINT_NOTNULL:
! {
! Datum arrayp;
! Datum *vals;
! int nelems;
! bool isnull;
! if (child_attnums == NIL)
! continue;
! arrayp = SysCacheGetAttr(CONSTROID, child_tuple,
! Anum_pg_constraint_conkey, &isnull);
! /* should not happen */
! Assert(!isnull);
! deconstruct_array(DatumGetArrayTypeP(arrayp), INT2OID, 2, true,
! 's', &vals, NULL, &nelems);
! Assert(nelems > 0);
!
! if (!list_member_int(child_attnums, DatumGetInt16(vals[0])))
! continue;
! break;
! }
! default:
! continue;
! }
/*
* OK, bump the child constraint's inheritance count. (If we fail
*************** MergeConstraintsIntoExisting(Relation ch
*** 7704,7711 ****
* surprise. But at least we'll never surprise by dropping columns someone
* isn't expecting to be dropped which would actually mean data loss.
*
! * coninhcount and conislocal for inherited constraints are adjusted in
! * exactly the same way.
*/
static void
ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
--- 8160,8167 ----
* surprise. But at least we'll never surprise by dropping columns someone
* isn't expecting to be dropped which would actually mean data loss.
*
! * coninhcount and conislocal for inherited CHECK and NOT NULL constraints
! * are adjusted in exactly the same way.
*/
static void
ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7718,7724 ****
attributeTuple,
constraintTuple,
depTuple;
! List *connames;
bool found = false;
/*
--- 8174,8180 ----
attributeTuple,
constraintTuple,
depTuple;
! List *constraints;
bool found = false;
/*
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7768,7773 ****
--- 8224,8231 ----
RelationGetRelationName(parent_rel),
RelationGetRelationName(rel))));
+ constraints = NIL;
+
/*
* Search through child columns looking for ones matching parent rel
*/
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7781,7786 ****
--- 8239,8245 ----
while (HeapTupleIsValid(attributeTuple = systable_getnext(scan)))
{
Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
+ HeapTuple parentattr_tuple;
/* Ignore if dropped or not inherited */
if (att->attisdropped)
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7788,7816 ****
if (att->attinhcount <= 0)
continue;
! if (SearchSysCacheExistsAttName(RelationGetRelid(parent_rel),
! NameStr(att->attname)))
{
/* Decrement inhcount and possibly set islocal to true */
HeapTuple copyTuple = heap_copytuple(attributeTuple);
Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
!
copy_att->attinhcount--;
if (copy_att->attinhcount == 0)
copy_att->attislocal = true;
simple_heap_update(catalogRelation, ©Tuple->t_self, copyTuple);
CatalogUpdateIndexes(catalogRelation, copyTuple);
heap_freetuple(copyTuple);
}
}
systable_endscan(scan);
heap_close(catalogRelation, RowExclusiveLock);
/*
! * Likewise, find inherited check constraints and disinherit them. To do
! * this, we first need a list of the names of the parent's check
! * constraints. (We cheat a bit by only checking for name matches,
* assuming that the expressions will match.)
*/
catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
--- 8247,8296 ----
if (att->attinhcount <= 0)
continue;
! parentattr_tuple = SearchSysCacheCopyAttName(RelationGetRelid(parent_rel),
! NameStr(att->attname));
!
! if (HeapTupleIsValid(parentattr_tuple))
{
/* Decrement inhcount and possibly set islocal to true */
HeapTuple copyTuple = heap_copytuple(attributeTuple);
Form_pg_attribute copy_att = (Form_pg_attribute) GETSTRUCT(copyTuple);
! Form_pg_attribute parent_att = (Form_pg_attribute) GETSTRUCT(parentattr_tuple);
!
copy_att->attinhcount--;
if (copy_att->attinhcount == 0)
copy_att->attislocal = true;
+
+ /*
+ * If attnotnull is set, record the inherited
+ * not null constraint. We save its attnum to deinherit
+ * its representation in pg_constraint below, but only when
+ * its ancestor has a NOT NULL constraint, too.
+ */
+ if (copy_att->attnotnull
+ && parent_att->attnotnull)
+ {
+ DeinheritConstraintInfo *inhInfo
+ = (DeinheritConstraintInfo *)palloc(sizeof(DeinheritConstraintInfo));
+ inhInfo->contype = CONSTRAINT_NOTNULL;
+ inhInfo->conname = NULL;
+ inhInfo->attnum = copy_att->attnum;
+ constraints = lappend(constraints, inhInfo);
+ }
simple_heap_update(catalogRelation, ©Tuple->t_self, copyTuple);
CatalogUpdateIndexes(catalogRelation, copyTuple);
heap_freetuple(copyTuple);
+ heap_freetuple(parentattr_tuple);
}
}
systable_endscan(scan);
heap_close(catalogRelation, RowExclusiveLock);
/*
! * Likewise, find inherited check and NOT NULL constraints and disinherit
! * them. To do this, we first need a list of the names of the parent's check
! * and NOT NULL constraints. (We cheat a bit by only checking for name matches,
* assuming that the expressions will match.)
*/
catalogRelation = heap_open(ConstraintRelationId, RowExclusiveLock);
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7821,7834 ****
scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
true, SnapshotNow, 1, key);
- connames = NIL;
-
while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
if (con->contype == CONSTRAINT_CHECK)
! connames = lappend(connames, pstrdup(NameStr(con->conname)));
}
systable_endscan(scan);
--- 8301,8319 ----
scan = systable_beginscan(catalogRelation, ConstraintRelidIndexId,
true, SnapshotNow, 1, key);
while (HeapTupleIsValid(constraintTuple = systable_getnext(scan)))
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
if (con->contype == CONSTRAINT_CHECK)
! {
! DeinheritConstraintInfo *inhInfo
! = (DeinheritConstraintInfo *)palloc(sizeof(DeinheritConstraintInfo));
! inhInfo->contype = CONSTRAINT_CHECK;
! inhInfo->conname = pstrdup(NameStr(con->conname));
! inhInfo->attnum = 0;
! constraints = lappend(constraints, inhInfo);
! }
}
systable_endscan(scan);
*************** ATExecDropInherit(Relation rel, RangeVar
*** 7846,7863 ****
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
bool match;
ListCell *lc;
! if (con->contype != CONSTRAINT_CHECK)
continue;
match = false;
! foreach(lc, connames)
{
! if (strcmp(NameStr(con->conname), (char *) lfirst(lc)) == 0)
{
match = true;
break;
}
}
if (match)
--- 8331,8379 ----
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(constraintTuple);
bool match;
ListCell *lc;
+ Datum arrayp;
+ Datum *keyvals;
+ int nelems;
+ bool isnull;
! if (con->contype != CONSTRAINT_CHECK
! && con->contype != CONSTRAINT_NOTNULL)
continue;
+ /*
+ * We scan through all constraints of the current child relation,
+ * checking for CONSTRAINT_CHECK and CONSTRAINT_NOTNULL occurrences.
+ *
+ * CHECK constraints are assumed to be named equally to in the
+ * relation's ancestor, while NOT NULL constraints always are attached
+ * to a specific column. Check for attnum and adjust the inheritance
+ * information accordingly.
+ */
+
match = false;
! foreach(lc, constraints)
{
! DeinheritConstraintInfo *inhInfo = (DeinheritConstraintInfo *) lfirst(lc);
!
! if ((inhInfo->contype == CONSTRAINT_CHECK)
! && (strcmp(NameStr(con->conname), inhInfo->conname) == 0))
{
match = true;
break;
}
+ else if (inhInfo->contype == CONSTRAINT_NOTNULL)
+ {
+ arrayp = SysCacheGetAttr(CONSTROID, constraintTuple,
+ Anum_pg_constraint_conkey, &isnull);
+
+ deconstruct_array(DatumGetArrayTypeP(arrayp), INT2OID, 2, true,
+ 's', &keyvals, NULL, &nelems);
+ if (keyvals[0] == inhInfo->attnum)
+ {
+ match = true;
+ break;
+ }
+ }
}
if (match)
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index af25c21..3ab752c 100644
*** a/src/backend/parser/parse_utilcmd.c
--- b/src/backend/parser/parse_utilcmd.c
*************** transformColumnDefinition(ParseState *ps
*** 466,471 ****
--- 466,472 ----
parser_errposition(pstate,
constraint->location)));
column->is_not_null = TRUE;
+ cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
saw_nullable = true;
break;
diff --git a/src/backend/port/pg_latch.c b/src/backend/port/pg_latch.c
index ...002f2f4 .
*** a/src/backend/port/pg_latch.c
--- b/src/backend/port/pg_latch.c
***************
*** 0 ****
--- 1 ----
+ ../../../src/backend/port/unix_latch.c
\ No newline at end of file
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index eece757..a6e8619 100644
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
*************** pg_get_constraintdef_worker(Oid constrai
*** 1071,1083 ****
if (fullCommand && OidIsValid(conForm->conrelid))
{
! appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
! generate_relation_name(conForm->conrelid, NIL),
! quote_identifier(NameStr(conForm->conname)));
}
switch (conForm->contype)
{
case CONSTRAINT_FOREIGN:
{
Datum val;
--- 1071,1112 ----
if (fullCommand && OidIsValid(conForm->conrelid))
{
! /* XXX: TODO, not sure how to handle this right now? */
! if (conForm->contype == CONSTRAINT_NOTNULL)
! {
! appendStringInfo(&buf, "ALTER TABLE ONLY %s ALTER COLUMN ",
! generate_relation_name(conForm->conrelid, NIL));
! }
! else
! {
! appendStringInfo(&buf, "ALTER TABLE ONLY %s ADD CONSTRAINT %s ",
! generate_relation_name(conForm->conrelid, NIL),
! quote_identifier(NameStr(conForm->conname)));
! }
}
switch (conForm->contype)
{
+ case CONSTRAINT_NOTNULL:
+ {
+ Datum val;
+ bool isnull;
+
+ /* XXX: TODO, not sure how to handle this right now? */
+
+ /* Fetch referenced column OID */
+ val = SysCacheGetAttr(CONSTROID, tup,
+ Anum_pg_constraint_conkey, &isnull);
+
+ /* Should not happen */
+ if (isnull)
+ elog(ERROR, "null conkey for constraint %u",
+ constraintId);
+
+ decompile_column_index_array(val, conForm->conrelid, &buf);
+ appendStringInfo(&buf, " SET NOT NULL");
+ break;
+ }
case CONSTRAINT_FOREIGN:
{
Datum val;
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 07db4a3..dda3dd5 100644
*** a/src/include/catalog/heap.h
--- b/src/include/catalog/heap.h
*************** extern List *AddRelationNewConstraints(R
*** 91,97 ****
bool is_local);
extern void StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr);
!
extern Node *cookDefault(ParseState *pstate,
Node *raw_default,
Oid atttypid,
--- 91,97 ----
bool is_local);
extern void StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr);
! extern void StoreColumnNotNullConstraint(Relation rel, CookedConstraint *cooked);
extern Node *cookDefault(ParseState *pstate,
Node *raw_default,
Oid atttypid,
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index ff87b6f..cd95391 100644
*** a/src/include/catalog/pg_constraint.h
--- b/src/include/catalog/pg_constraint.h
*************** typedef FormData_pg_constraint *Form_pg_
*** 175,180 ****
--- 175,181 ----
/* Valid values for contype */
#define CONSTRAINT_CHECK 'c'
+ #define CONSTRAINT_NOTNULL 'n'
#define CONSTRAINT_FOREIGN 'f'
#define CONSTRAINT_PRIMARY 'p'
#define CONSTRAINT_UNIQUE 'u'
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index e896dc7..8364b27 100644
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef enum AlterTableType
*** 1116,1122 ****
--- 1116,1124 ----
AT_AddColumnToView, /* implicitly via CREATE OR REPLACE VIEW */
AT_ColumnDefault, /* alter column default */
AT_DropNotNull, /* alter column drop not null */
+ AT_DropNotNullRecurse, /* internal to commands/tablecmds.c */
AT_SetNotNull, /* alter column set not null */
+ AT_SetNotNullRecurse, /* internal to commands/tablecmds.c */
AT_SetStatistics, /* alter column set statistics */
AT_SetOptions, /* alter column set ( options ) */
AT_ResetOptions, /* alter column reset ( options ) */
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 83e24fd..9afd2bd 100644
*** a/src/test/regress/expected/alter_table.out
--- b/src/test/regress/expected/alter_table.out
*************** alter table atacc1 alter bar drop not nu
*** 593,601 ****
ERROR: column "bar" of relation "atacc1" does not exist
-- try altering the oid column, should fail
alter table atacc1 alter oid set not null;
! ERROR: cannot alter system column "oid"
alter table atacc1 alter oid drop not null;
! ERROR: cannot alter system column "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;
--- 593,601 ----
ERROR: column "bar" of relation "atacc1" does not exist
-- try altering the oid column, should fail
alter table atacc1 alter oid set not null;
! ERROR: cannot alter system column "oid" of relation "atacc1"
alter table atacc1 alter oid drop not null;
! ERROR: cannot alter system column "oid" of relation "atacc1"
-- 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;
diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out
index 96bd816..6d0e3e1 100644
*** a/src/test/regress/expected/cluster.out
--- b/src/test/regress/expected/cluster.out
*************** ERROR: insert or update on table "clstr
*** 251,261 ****
DETAIL: Key (b)=(1111) is not present in table "clstr_tst_s".
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass
ORDER BY 1;
! conname
! ----------------
clstr_tst_con
clstr_tst_pkey
! (2 rows)
SELECT relname, relkind,
EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast
--- 251,262 ----
DETAIL: Key (b)=(1111) is not present in table "clstr_tst_s".
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass
ORDER BY 1;
! conname
! ----------------------
! clstr_tst_a_not_null
clstr_tst_con
clstr_tst_pkey
! (3 rows)
SELECT relname, relkind,
EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast