in transformColumnDefinition we can add parser_errposition for the error report. if (column->is_not_null && column->generated == ATTRIBUTE_GENERATED_VIRTUAL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("not-null constraints are not supported on virtual generated columns"), parser_errposition(cxt->pstate, constraint->location))); sometimes, it points to the word "generated", sometimes "not". I guess this should be fine. example: create table t13 (a int, b bool generated always as ((true )) VIRTUAL not null); create table t13 (a int, b bool not null generated always as ((true )) VIRTUAL);
These 3 functions will call StoreRelNotNull to store the not-null constraint. StoreConstraints AddRelationNotNullConstraints AddRelationNewConstraints we can disallow not-null on virtual generated columns via these 3 functions. I guess we don't want to add more complexity to AddRelationNotNullConstraints. we can do it in StoreRelNotNull. like: @@ -2185,8 +2196,19 @@ StoreRelNotNull(Relation rel, const char *nnname, AttrNumber attnum, { Oid constrOid; + TupleDesc tupdesc; + Form_pg_attribute att; Assert(attnum > InvalidAttrNumber); + tupdesc = RelationGetDescr(rel); + att = TupleDescAttr(tupdesc, attnum - 1); + + if (att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("not-null constraints are not supported on virtual generated columns"), + errdetail("Column \"%s\" of relation \"%s\" is a virtual generated column.", + NameStr(att->attname), RelationGetRelationName(rel)))); related tests: create table t12(b int, a int generated always as (11) virtual, constraint nn not null a); create table t12(b int, constraint nn not null a, a int generated always as (11) virtual); drop table if exists t14; create table t14(b int, a int generated always as (11) virtual); alter table t14 add constraint nn not null a; alter table t14 add constraint nn not null a no inherit;