• Tom Lane's avatar
    Fix handling of targetlist SRFs when scan/join relation is known empty. · 1d338584
    Tom Lane authored
    When we introduced separate ProjectSetPath nodes for application of
    set-returning functions in v10, we inadvertently broke some cases where
    we're supposed to recognize that the result of a subquery is known to be
    empty (contain zero rows).  That's because IS_DUMMY_REL was just looking
    for a childless AppendPath without allowing for a ProjectSetPath being
    possibly stuck on top.  In itself, this didn't do anything much worse
    than produce slightly worse plans for some corner cases.
    
    Then in v11, commit 11cf92f6 rearranged things to allow the scan/join
    targetlist to be applied directly to partial paths before they get
    gathered.  But it inserted a short-circuit path for dummy relations
    that was a little too short: it failed to insert a ProjectSetPath node
    at all for a targetlist containing set-returning functions, resulting in
    bogus "set-valued function called in context that cannot accept a set"
    errors, as reported in bug #15669 from Madelaine Thibaut.
    
    The best way to fix this mess seems to be to reimplement IS_DUMMY_REL
    so that it drills down through any ProjectSetPath nodes that might be
    there (and it seems like we'd better allow for ProjectionPath as well).
    
    While we're at it, make it look at rel->pathlist not cheapest_total_path,
    so that it gives the right answer independently of whether set_cheapest
    has been done lately.  That dependency looks pretty shaky in the context
    of code like apply_scanjoin_target_to_paths, and even if it's not broken
    today it'd certainly bite us at some point.  (Nastily, unsafe use of the
    old coding would almost always work; the hazard comes down to possibly
    looking through a dangling pointer, and only once in a blue moon would
    you find something there that resulted in the wrong answer.)
    
    It now looks like it was a mistake for IS_DUMMY_REL to be a macro: if
    there are any extensions using it, they'll continue to use the old
    inadequate logic until they're recompiled, after which they'll fail
    to load into server versions predating this fix.  Hopefully there are
    few such extensions.
    
    Having fixed IS_DUMMY_REL, the special path for dummy rels in
    apply_scanjoin_target_to_paths is unnecessary as well as being wrong,
    so we can just drop it.
    
    Also change a few places that were testing for partitioned-ness of a
    planner relation but not using IS_PARTITIONED_REL for the purpose; that
    seems unsafe as well as inconsistent, plus it required an ugly hack in
    apply_scanjoin_target_to_paths.
    
    In passing, save a few cycles in apply_scanjoin_target_to_paths by
    skipping processing of pre-existing paths for partitioned rels,
    and do some cosmetic cleanup and comment adjustment in that function.
    
    I renamed IS_DUMMY_PATH to IS_DUMMY_APPEND with the intention of breaking
    any code that might be using it, since in almost every case that would
    be wrong; IS_DUMMY_REL is what to be using instead.
    
    In HEAD, also make set_dummy_rel_pathlist static (since it's no longer
    used from outside allpaths.c), and delete is_dummy_plan, since it's no
    longer used anywhere.
    
    Back-patch as appropriate into v11 and v10.
    
    Tom Lane and Julien Rouhaud
    
    Discussion: https://postgr.es/m/15669-02fb3296cca26203@postgresql.org
    1d338584
planner.c 230 KB