On Sun, Feb 9, 2025 at 7:02 PM Zhang Mingli <zmlpostg...@gmail.com> wrote:
> On Feb 9, 2025 at 16:00 +0800, Alexander Lakhin <exclus...@gmail.com>, wrote:
> Please look at a planner error with a virtual generated column triggered
> by the following script:
> CREATE TABLE t(a int, b int GENERATED ALWAYS AS (a * 1));
>
> SELECT SUM(CASE WHEN t.b = 1 THEN 1 ELSE 1 END) OVER (PARTITION BY t.a)
> FROM t AS t1 LEFT JOIN T ON true;
>
> ERROR:  XX000: wrong varnullingrels (b) (expected (b 3)) for Var 2/1
> LOCATION:  search_indexed_tlist_for_var, setrefs.c:2901

> During the parse stage, we set the Var->varnullingrels in the 
> parse_analyze_fixedparams function.
> Later, when rewriting the parse tree in pg_rewrite_query() to expand virtual 
> columns, we replace the expression column b with a new Var that includes a, 
> since b is defined as a * 1.
> Unfortunately, we overlooked updating the Var->varnullingrels at this point.
> As a result, when we enter search_indexed_tlist_for_var, it leads to a 
> failure.
> While we do have another target entry with the correct varnullingrels, the 
> expression involving the virtual column generates another column reference, 
> which causes the error.
> Currently, I don't have a solid fix.
> One potential solution is to correct the Vars at or after the rewrite stage 
> by traversing the parse tree again using markNullableIfNeeded.
> However, this approach may require exposing the ParseState, which doesn't 
> seem ideal.
> It appears that the virtual column generation function during the rewrite 
> stage does not account for the Var field settings, leading to the errors we 
> are encountering.

Hmm, would it be possible to propagate any varnullingrels into the
replacement expression in ReplaceVarsFromTargetList_callback()?

BTW, I was curious about what happens if the replacement expression is
constant, so I tried running the query below.

CREATE TABLE t (a int, b int GENERATED ALWAYS AS (1 + 1));
INSERT INTO t VALUES (1);
INSERT INTO t VALUES (2);

# SELECT t2.a, t2.b FROM t t1 LEFT JOIN t t2 ON FALSE;
 a | b
---+---
   | 2
   | 2
(2 rows)

Is this the expected behavior?  I was expecting that t2.b should be
all NULLs.

Thanks
Richard


Reply via email to