RE: batch fdw insert bug (Postgres 14) - Mailing list pgsql-hackers

From houzj.fnst@fujitsu.com
Subject RE: batch fdw insert bug (Postgres 14)
Date
Msg-id OS0PR01MB5716743FF4AD2851AAB9D41A94579@OS0PR01MB5716.jpnprd01.prod.outlook.com
Whole thread Raw
In response to Re: batch fdw insert bug (Postgres 14)  (Pavel Stehule <pavel.stehule@gmail.com>)
Responses Re: batch fdw insert bug (Postgres 14)
List pgsql-hackers
>  I am testing new features in Postgres 14, and I found bug 
> EXPLAIN ANALYZE VERBOSE  for insert to FDW table with batch_size 1000 returns
>
-------------------------------------------------------------------------------------------------------------------------------
> Insert on public.vzdalena_tabulka2  (cost=0.00..175.00 rows=0 width=0) (actual time=30.269..30.270 rows=0 loops=1)
>   Remote SQL:
\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F\x7F
>   Batch Size: 1000
>   ->  Function Scan on pg_catalog.generate_series g  (cost=0.00..175.00 rows=10000 width=36) (actual
time=0.453..1.988rows=10
 
>         Output: g.i, ('AHOJ'::text || (g.i)::text)
>         Function Call: generate_series(1, 10000)
> Planning Time: 0.075 ms
> Execution Time: 31.032 ms
> (8 rows)
> reproducer

I can reproduce the issue and did some basic analysis on it.

The "Remote SQL" is built from the following code:

----------------
        char       *sql = strVal(list_nth(fdw_private,
                                          FdwModifyPrivateUpdateSql));

        ExplainPropertyText("Remote SQL", sql, es);
---------------

It use the query string stored in list fdw_private.
However, the "fmstate->query" will also point to the string in fdw_private,
by  postgresBeginForeignModify --> create_foreign_modify --> "fmstate->query = query;"

And in execute_foreign_modify(), " fmstate->query "  will be freed when rebuild the query
string to do the batch insert like the following:

----------------
if (operation == CMD_INSERT && fmstate->num_slots != *numSlots)         
{                                                                       
...                                           
        /* Build INSERT string with numSlots records in its VALUES clause. */
        initStringInfo(&sql);                                           
        rebuildInsertSql(&sql, fmstate->orig_query, fmstate->values_end,
                                         fmstate->p_nums, *numSlots - 1)
**      pfree(fmstate->query);                                          
        fmstate->query = sql.data;
----------------

So, it output the freed pointer as "Remote SQL".

For the fix.
The query string could be rebuilt depending on the numSlots,
which query string should be output ?
should we just output the original query string like the attached patch ?
Or should we output the last one?

Best regards,
houzj

Attachment

pgsql-hackers by date:

Previous
From: Dilip Kumar
Date:
Subject: Re: Logical Replication - behavior of TRUNCATE ... CASCADE
Next
From: Jeevan Ladhe
Date:
Subject: Re: Query regarding RANGE Partitioning