Re: BUG #18077: PostgreSQL server subprocess crashed by a SELECT statement with WITH clause

Richard Guo <guofenglinux@gmail.com>

From: Richard Guo <guofenglinux@gmail.com>
To: fuboat@outlook.com, pgsql-bugs@lists.postgresql.org
Date: 2023-08-30T12:03:55Z
Lists: pgsql-bugs

Attachments

On Wed, Aug 30, 2023 at 7:42 PM Richard Guo <guofenglinux@gmail.com> wrote:

> On Wed, Aug 30, 2023 at 4:06 PM PG Bug reporting form <
> noreply@postgresql.org> wrote:
>
>> PostgreSQL server subprocess crashed by a SELECT statement with WITH
>> clause.
>> It did not affect the main process. It can be reproduced on PostgreSQL
>> 15.4.
>>
>> PoC:
>> ```sql
>> WITH x ( x ) AS ( SELECT ( 1 , 'x' ) ) SELECT FROM x WHERE ( SELECT FROM (
>> SELECT x ) x WHERE ( SELECT x ( x ) ) )
>> ```
>
>
> Thanks for the report!  Reproduced here on HEAD.  I looked into it a
> little bit and it seems that when we expand a Var of type RECORD from a
> RTE_SUBQUERY, we mess up with the level of ParseState.  For example,
>
> select * from (SELECT(1, 'a')) as t(c)
> WHERE (SELECT * FROM (SELECT c as c1) s
>        WHERE (select * from func(c1) f));
>
> When we expand Var 'c1' from func(c1), we figure out that it comes from
> subquery 's'.  When we recurse into subquery 's', we just build an
> additional level of ParseState atop the current ParseState, which seems
> not correct.  Shouldn't we climb up by the nesting depth first before we
> build the additional level of ParseState?  Something like
>
> --- a/src/backend/parser/parse_target.c
> +++ b/src/backend/parser/parse_target.c
> @@ -1591,6 +1591,12 @@ expandRecordVariable(ParseState *pstate, Var *var,
> int levelsup)
>                      */
>                     ParseState  mypstate = {0};
>
> +                   for (int i = 0; i < netlevelsup; i++)
> +                   {
> +                       pstate = pstate->parentParseState;
> +                       Assert(pstate != NULL);
> +                   }
> +
>                     mypstate.parentParseState = pstate;
>                     mypstate.p_rtable = rte->subquery->rtable;
>

Here is the patch.

Thanks
Richard

Commits

  1. Track nesting depth correctly when drilling down into RECORD Vars.

  2. Fix get_expr_result_type() to find field names for RECORD Consts.

  3. Allow extracting fields from a ROW() expression in more cases.