]> granicus.if.org Git - postgresql/commit
Fix mishandling of tSRFs at different nesting levels.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Feb 2017 21:38:13 +0000 (16:38 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 2 Feb 2017 21:38:18 +0000 (16:38 -0500)
commitc82d4e658eff287846fe6243966d110ff4ae9025
treec9ccd32074292500c43e613e190e5c674ba10569
parentecb814b5cef4971e50ee177eff320d416aa0b882
Fix mishandling of tSRFs at different nesting levels.

Given a targetlist like "srf(x), f(srf(x))", split_pathtarget_at_srfs()
decided that it needed two levels of ProjectSet nodes, failing to notice
that the two SRF calls are textually equal().  Because of that, setrefs.c
would convert the upper ProjectSet's tlist to "Var1, f(Var1)" (where Var1
represents a reference to the srf(x) output of the lower ProjectSet).
This triggered an assertion in nodeProjectSet.c complaining that it found
no SRFs to evaluate, as reported by Erik Rijkers.

What we want in such a case is to evaluate srf(x) only once and use a plain
Result node to compute "Var1, f(Var1)"; that gives results similar to what
previous versions produced, whereas allowing srf(x) to be evaluated again
in an upper ProjectSet would square the number of rows emitted.

Furthermore, even if the SRF calls aren't textually identical, we want them
to be evaluated in lockstep, because that's what happened in the old
implementation.  But split_pathtarget_at_srfs() got this completely wrong,
using two levels of ProjectSet for a case like "srf(x), f(srf(y))".

Hence, rewrite split_pathtarget_at_srfs() from the ground up so that it
groups SRFs according to the depth of nesting of SRFs in their arguments.
This is pretty much how we envisioned that working originally, but I blew
it when it came to implementation.

In passing, optimize the case of target == input_target, which I noticed
is not only possible but quite common.

Discussion: https://postgr.es/m/dcbd2853c05d22088766553d60dc78c6@xs4all.nl
src/backend/optimizer/util/tlist.c
src/test/regress/expected/subselect.out
src/test/regress/expected/tsrf.out
src/test/regress/sql/tsrf.sql