Hi,

forget to add hackers to cc.

Xuneng Zhou <xunengz...@gmail.com> 于2025年3月8日周六 12:10写道:

>
>
> Navneet Kumar <thanit3...@gmail.com> 于2025年3月8日周六 02:09写道:
>
>>
>>
>>> This scenario fails
>>> 1. CREATE TABLE person (
>>>     id INT GENERATED BY DEFAULT AS IDENTITY,
>>>     first_name VARCHAR(50) NOT NULL,
>>>     last_name VARCHAR(50) NOT NULL
>>> );
>>>
>>> 2. INSERT INTO person (first_name, last_name)
>>> VALUES ('first', 'last');
>>>
>>> 3. ALTER TABLE person
>>> ADD COLUMN full_name VARCHAR(100) GENERATED ALWAYS AS (first_name || ' '
>>> || last_name) VIRTUAL;
>>>
>>
>> Forgot to mention NOT NULL constraint in above query.
>>
>> 3. ALTER TABLE person
>> ADD COLUMN full_name VARCHAR(100) NOT NULL GENERATED ALWAYS AS
>> (first_name || ' ' || last_name) VIRTUAL;
>>
>> ERROR:  column "full_name" of relation "person" contains null values
>>
>>
>
> I did some debugging for this error.  It is reported in this function:
>
> */**
>
> * * ATRewriteTable: scan or rewrite one table*
>
> * **
>
> * * A rewrite is requested by passing a valid OIDNewHeap; in that case,
> caller*
>
> * * must already hold AccessExclusiveLock on it.*
>
> * */*
>
> static void
>
> *ATRewriteTable*(AlteredTableInfo **tab*, Oid *OIDNewHeap*)
>
> {
>
>
>
>             .......
>
>
> *            /* Now check any constraints on the possibly-changed tuple */*
>
>             econtext->ecxt_scantuple = insertslot;
>
>
>             foreach(l, notnull_attrs)
>
>             {
>
>                 int         attn = lfirst_int(l);
>
>
>                 if (*slot_attisnull*(insertslot, attn + 1))
>
>                 {
>
>                     Form_pg_attribute attr = *TupleDescAttr*(newTupDesc,
> attn);
>
>
>                     ereport(ERROR,
>
>                             (*errcode*(ERRCODE_NOT_NULL_VIOLATION),
>
>                              *errmsg*("column \"%s\" of relation \"%s\"
> contains null values",
>
>                                     NameStr(attr->attname),
>
>                                     RelationGetRelationName(oldrel)),
>
>                              *errtablecol*(oldrel, attn + 1)));
>
>                 }
>
>             }
>
>         .......
>
> }
>
>
> If this error is unexpected, I think the issue is that when adding a NOT
> NULL constraint to a regular column, pg scans the table to ensure no NULL
> values exist. But for virtual columns, there are no stored values to scan.
> Maybe we should add some condition like this? Then checking not null at
> runtime.
>
>
> * /* Skip NOT NULL validation for virtual generated columns during table
> rewrite */*
>
>     if (TupleDescAttr(newTupDesc, attn)->attgenerated ==
> ATTRIBUTE_GENERATED_VIRTUAL)
>
>         continue;
>

Reply via email to