Re: 'update returning *' returns 0 columns instead of empty row with2 columns when (i) no rows updated and (ii) when applied to a partitionedtable with sub-partition

Поиск
Список
Период
Сортировка
От Amit Langote
Тема Re: 'update returning *' returns 0 columns instead of empty row with2 columns when (i) no rows updated and (ii) when applied to a partitionedtable with sub-partition
Дата
Msg-id 42050d24-e037-9e6b-79d5-eaf40a28dd3b@lab.ntt.co.jp
обсуждение исходный текст
Ответ на Re: 'update returning *' returns 0 columns instead of empty row with2 columns when (i) no rows updated and (ii) when applied to a partitionedtable with sub-partition  (Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>)
Список pgsql-bugs
On 2019/02/06 16:35, Amit Langote wrote:
> Hi,
> 
> On 2019/02/01 23:32, Petr Fedorov wrote:
>> Hello,
>>
>> The following code snippet demonstrates the problem: the first select
>> passes and the second [select * from testf(FALSE)] fails. I would expect
>> that select * from testf(...); works without errors in both cases.
>>
>> begin;
>>
>> create table test (id integer, data char(1)) partition by list (id)
>> tablespace pg_default;
>> create table test_1 partition of test for values in (1) partition by
>> list (data);
>> create table test_1_a partition of test_1 for values in ('a');
>> create function testf(p boolean) returns setof test language 'plpgsql'
>> as $body$ begin return query update test set id=id where p returning *;
>> end; $body$;
>> insert into test (id, data) values (1, 'a');
>> select * from testf(TRUE);
>> select * from testf(FALSE);
>>
>> rollback;   
>>
>> The result:
>>
>> ERROR: structure of query does not match function result type
>>
>> SQL state: 42804
>>
>> Detail: Number of returned columns (0) does not match expected column
>> count (2).
>>
>> Context: PL/pgSQL function testf(boolean) line 1 at RETURN QUERY
> 
> Thanks for the report.  There indeed appears to be a bug here.
> 
> The problem seems to be with how planner handles an empty plan (due to
> constant-FALSE qual) when the target table is an inheritance tree.  OP's
> example contains a partitioned table, but I could reproduce it with
> regular inheritance:
> 
> create table parent (id int);
> create table child () inherits (parent);
> create or replace function testf(p boolean) returns setof parent
>   language 'plpgsql' as $body$
>     begin
>       return query update parent set id = id where p returning *;
>     end;
> $body$;
> 
> select * from testf(true);
>  id
> ────
> (0 rows)
> 
> select * from testf(false);
> ERROR:  structure of query does not match function result type
> DETAIL:  Number of returned columns (0) does not match expected column
> count (1).
> CONTEXT:  PL/pgSQL function testf(boolean) line 1 at RETURN QUERY
> 
> No problem when there is no inheritance:
> 
> drop function testf;
> create table foo (like parent);
> create or replace function testf(p boolean) returns setof foo
>   language 'plpgsql' as $body$
>     begin
>       return query update foo set id = id where p returning *;
>     end;
> $body$;
> select * from testf(false);
>  id
> ────
> (0 rows)
> 
> 
> Mismatch between the query result type and the function result type occurs
> in the inheritance case, because the targetlist of the plan for the UPDATE
> query in testf's body is empty, whereas the function execution code
> (pl_exec.c) expects it match the function's result type (set of parent).
> It's empty because inheritance_planner sets an empty Result path when it
> finds that all the children are excluded, but hasn't generated enough
> state in the path's RelOptInfo and PlannerInfo such that the correct
> targetlist could be set in the empty Result plan that's eventually created.
> 
> Attached patch seems to fix it.  It also adds a test in inherit.sql.
> 
> Thoughts?

Will add this to next CF.

Thanks,
Amit



В списке pgsql-bugs по дате отправления:

Предыдущее
От: Amit Langote
Дата:
Сообщение: Re: BUG #15623: Inconsistent use of default for updatable view
Следующее
От: Michael Paquier
Дата:
Сообщение: Re: BUG #15631: Generated as identity field in a temporary tablewith on commit drop corrupts system catalogs