On 2025-Sep-04, jian he wrote:
> @@ -3093,6 +3115,16 @@ AddRelationNotNullConstraints(Relation rel, List
> *constraints,
> conname = other->name;
>
> inhcount++;
> +
> + /*
> + * if a column inherit multiple not-null
> constraints, the
> + * enforced status should the same.
> + */
> + if (other->is_enforced != cooked->is_enforced)
> + ereport(ERROR,
> +
> errcode(ERRCODE_DATATYPE_MISMATCH),
> + errmsg("cannot define
> not-null constraint on column \"%s\"", conname),
> + errdetail("The column
> inherited not-null constraints have conflict ENFORCED status."));
> old_notnulls =
> list_delete_nth_cell(old_notnulls, restpos);
> }
> else
Hmmm, are you sure about this? I think if a table has two parents, one
with enforced and the other with not enforced constraint, then it's okay
to get them combined resulting in one enforced constraint.
> @@ -777,6 +778,18 @@ AdjustNotNullInheritance(Oid relid, AttrNumber attnum,
> errhint("You might need to validate it
> using %s.",
> "ALTER TABLE ...
> VALIDATE CONSTRAINT"));
>
> + /*
> + * If the ENFORCED status we're asked for doesn't match what the
> + * existing constraint has, throw an error.
> + */
> + if (is_enforced != conform->conenforced)
> + ereport(ERROR,
> +
> errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
> + errmsg("cannot change ENFORCED status
> of NOT NULL constraint \"%s\" on relation \"%s\"",
> + NameStr(conform->conname),
> get_rel_name(relid)),
> + errhint("You might need to drop the
> existing not enforced constraint using %s.",
> + "ALTER TABLE ... DROP
> CONSTRAINT"));
I think the hint here should suggest to make the existing constraint as
enforced, rather than drop it.
> @@ -9937,9 +9962,9 @@ ATAddCheckNNConstraint(List **wqueue, AlteredTableInfo
> *tab, Relation rel,
> * If adding a valid not-null constraint, set the pg_attribute
> flag
> * and tell phase 3 to verify existing rows, if needed. For an
> * invalid constraint, just set attnotnull, without queueing
> - * verification.
> + * verification. For not enforced not-null, no need set
> attnotnull.
> */
> - if (constr->contype == CONSTR_NOTNULL)
> + if (constr->contype == CONSTR_NOTNULL && ccon->is_enforced)
> set_attnotnull(wqueue, rel, ccon->attnum,
> !constr->skip_validation,
> !constr->skip_validation);
Didn't we decide that attnotnull meant whether a constraint exists at
all, without making a judgement on whether it's enforced or valid? The
important change should be in CheckNNConstraintFetch() which should
determine attnullability in a way that allows executor know whether the
column is nullable or not. I admit we might want to handle this
differently for unenforced constraints, but we should discuss that and
make sure that's what we want.
> + else if (notenforced)
> + {
> + /*
> + * We can't use ATExecSetNotNull here because it adds
> an enforced
> + * not-null constraint, but here we only want a
> non-enforced one.
> + */
Umm, wouldn't it make more sense to modify ATExecSetNotNull() so that it
does what we want? This seems hackish.
> @@ -1272,33 +1294,41 @@ transformTableLikeClause(CreateStmtContext *cxt,
> TableLikeClause *table_like_cla
> * Reproduce not-null constraints, if any, by copying them. We do this
> * regardless of options given.
> */
> - if (tupleDesc->constr && tupleDesc->constr->has_not_null)
> - {
> - List *lst;
> + lst = RelationGetNotNullConstraints(RelationGetRelid(relation), false,
> +
> true);
> + cxt->nnconstraints = list_concat(cxt->nnconstraints, lst);
>
> - lst = RelationGetNotNullConstraints(RelationGetRelid(relation),
> false,
> -
> true);
> + /*
> + * When creating a new relation, marking the enforced not-null
> constraint as
> + * not valid doesn't make sense, so we treat it as valid.
> + */
> + foreach_node(Constraint, nnconstr, lst)
> + {
> + if (nnconstr->is_enforced)
> + {
> + nnconstr->skip_validation = false;
> + nnconstr->initially_valid = true;
> + }
> + }
Hmmm, this bit here (making constraints as valid if they're not valid in
the source table) looks like a fix for the existing code. I think it
should be a separate patch, perhaps back-patchable to 18. Or maybe I'm
missing something ...?
--
Álvaro Herrera 48°01'N 7°57'E — https://www.EnterpriseDB.com/
"Digital and video cameras have this adjustment and film cameras don't for the
same reason dogs and cats lick themselves: because they can." (Ken Rockwell)