Thread

  1. Re: Function scan FDW pushdown

    Alexander Pyhalov <a.pyhalov@postgrespro.ru> — 2026-05-20T10:17:04Z

    Alexander Korotkov писал(а) 2026-05-19 21:21:
    > Good evening!
    > 
    > On Tue, May 19, 2026 at 6:25 PM Alexander Pyhalov
    > <a.pyhalov@postgrespro.ru> wrote:
    >> 
    >> Found one more issue in whole row var deparsing. It can appear on a
    >> nullable outer side, and we should use the same logic as when 
    >> deparsing
    >> table column reference. Otherwise we get records from nulls instead of
    >> nulls (for example, "(NULL, NULL)" instead of NULL).
    > 
    > 
    > Good catch, accepted.
    > 
    
    Hi.
    
    I've found another issue. The fact that in the new versions of the patch 
    RTE RelOptInfo misses fdw_private seems to be unfortunate. For example, 
    in the last version we haven't thought about classifying 
    baserestrictinfo. And if we do, we should pass fdw_private down to 
    foreign_expr_walker. Perhaps, we could attach it to RTE_FUNCTION rel 
    prior to calling classifyConditions(), but should we later set it back 
    to NULL? Another problem comes if we try to handle joins,  which can 
    crearte subqueries (like INNER/OUTER UNIQUE). In this case we should 
    somehow cook fpinfo for get_relation_column_alias_ids(). Attaching patch 
    which tries to handle baserestrictinfos by passing fpinfo down to 
    foreign_expr_walker().
    
    One more interesting example (included in the patch) is
    
    EXPLAIN (VERBOSE, COSTS OFF)
    WITH s AS MATERIALIZED (SELECT r1.* FROM remote_tbl r1
    JOIN LATERAL
    (SELECT r2.a FROM remote_tbl r2, f(r1.a) LIMIT 1) s
    ON true)
    SELECT * FROM s ORDER BY 1;
    
    We get the following plan:
    
      Sort
        Output: s.a, s.b
        Sort Key: s.a
        CTE s
          ->  Nested Loop
                Output: r1.a, r1.b
                ->  Foreign Scan on public.remote_tbl r1
                      Output: r1.a, r1.b
                      Remote SQL: SELECT a, b FROM public.base_tbl_fn
                ->  Foreign Scan
                      Output: NULL::integer
                      Relations: (public.remote_tbl r2) INNER JOIN (Function 
    f)
                      Remote SQL: SELECT NULL FROM (public.base_tbl_fn r1 
    INNER JOIN public.f($1::integer) f2(c1) ON (TRUE)) LIMIT 1::bigint
        ->  CTE Scan on s
              Output: s.a, s.b
    
    Here you can see that we use parameter in function argument. Don't know 
    if it's a real problem, but at least looks suspicious. In v3 patch used 
    contain_param_walker() in is_nonrel_relinfo_ok() (which mutated to 
    function_rte_pushdown_ok()) to avoid such plans.
    
    One minor issue I've noticed is in function_rte_pushdown_ok():
    +       if (rel->rtekind != RTE_FUNCTION)
    +               return false;
    +       rte = planner_rt_fetch(rel->relid, root);
    +       if (rte->rtekind != RTE_FUNCTION)
    +               return false;
    
    Is the second rtekind check necessary?
    -- 
    Best regards,
    Alexander Pyhalov,
    Postgres Professional