[BUG] ON CONFLICT DO UPDATE SET x = EXCLUDED. errors or silently writes NULL - Mailing list pgsql-hackers

From SATYANARAYANA NARLAPURAM
Subject [BUG] ON CONFLICT DO UPDATE SET x = EXCLUDED. errors or silently writes NULL
Date
Msg-id CAHg+QDf7wTLz_vqb1wi1EJ_4Uh+Vxm75+b4c-Ky=6P+yOAHjbQ@mail.gmail.com
Whole thread
Responses Re: [BUG] ON CONFLICT DO UPDATE SET x = EXCLUDED. errors or silently writes NULL
List pgsql-hackers
Hi Hackers,

Virtual generated column (bgc) behavior for plain and partitioned tables is different
when EXCLUDED.<vgc> references inside for INSERT ... ON CONFLICT DO UPDATE.
For plain table it errors out with the message "unexpected virtual generated column reference"
and for partitioned tables, it silently writes NULL (wrong data).


Repro:

-- plan table

    DROP TABLE IF EXISTS t;
    CREATE TABLE t (id int PRIMARY KEY,
                    a  int,
                    c  int GENERATED ALWAYS AS (a * 10) VIRTUAL);
    INSERT INTO t VALUES (1, 5);

    INSERT INTO t VALUES (1, 7)
        ON CONFLICT (id) DO UPDATE SET a = EXCLUDED.c;
    -- ERROR:  unexpected virtual generated column reference
   

-- Partitioned table: 

    DROP TABLE IF EXISTS tp;
    CREATE TABLE tp (id int PRIMARY KEY,
                     a  int,
                     c  int GENERATED ALWAYS AS (a * 10) VIRTUAL)
        PARTITION BY RANGE (id);
    CREATE TABLE tp1 PARTITION OF tp FOR VALUES FROM (1) TO (100);
    INSERT INTO tp VALUES (1, 5);

    INSERT INTO tp VALUES (1, 7)
        ON CONFLICT (id) DO UPDATE SET a = EXCLUDED.c;

    SELECT * FROM tp

 id | a | c
----+---+---
  1 |   |  


We have two options to fix, (1) throw an error for partitioned tables similar to plain tables or
(2) support the scenario fixing for both the cases.

I tried fixing this by replacing build_tlist_index with build_tlist_index_other_vars . This fix
works because build_tlist_index_other_vars only indexes plain-Var TEs of exclRelTlist and 
leaves has_non_vars = false, so fix_join_expr skips whole-subtree matching and never collapses
 the VGC-expanded (EXCLUDED.a * 10) in onConflictSet back into a Var(INNER_VAR, vgc_attno).

I am not super familiar with this area so I am not sure if this breaks anything. Ran the existing 
tests and they seem to be passing.


Thanks,
Satya 
Attachment

pgsql-hackers by date:

Previous
From: John Mikk
Date:
Subject: Re: POC: Comparison of partitioning key values
Next
From: Andrew Dunstan
Date:
Subject: Re: Add errdetail() with PID and UID about source of termination signal