> pavel.steh...@gmail.com wrote:
> 
> b...@yugabyte.com <mailto:b...@yugabyte.com> wrote:
> 
>> pavel.steh...@gmail.com <mailto:pavel.steh...@gmail.com> wrote:
>> 
>>> t...@sss.pgh.pa.us <mailto:t...@sss.pgh.pa.us> wrote:
>>> 
>>>> pavel.steh...@gmail.com <mailto:pavel.steh...@gmail.com> wrote:
>>>> 
>>>> Some errors like this, but not this can be detected by plpgsql_check
>>>> https://github.com/okbob/plpgsql_check 
>>>> <https://www.google.com/url?q=https://github.com/okbob/plpgsql_check&source=gmail-imap&ust=1629227921000000&usg=AOvVaw3Et9tiGoSScn4bG0DPyF8J>
>>>> probably the heuristic for type check is not complete.
>>> 
>>> STRICTMULTIASSIGNMENT would detect most cases of this, except that the 
>>> condition is checked too late.  We'd need to count the fields *before* 
>>> trying to assign values, not after.
>>> 
>>> In the meantime, it does seem like the docs could be more explicit about 
>>> this, and perhaps give an example showing the (x).* solution.
>> 
>> Yes, a more detailed explanation of this behavior can be nice.  There can be 
>> an example of value unnesting, but I think so for this case, there should be 
>> mainly an example of ANSI assign syntax.
>> 
>> var := (SELECT x FROM ..)
>> 
>> This syntax has advantages so is not amigonuous for this case, and explicit 
>> unnesting is not necessary (and it is not possible). Moreover, this is ANSI 
>> SQL syntax.
> 
> Consider this example:
> 
> create type type1 as (a1 int, a2 int);
> create table tab1(k int primary key, b boolean not null, t type1 not null);
> insert into tab1(k, b, t) values(1, true, (10, 20));
> select b::text, t::text from tab1 where k = 1;
> 
> It seems to be perfectly plausible—and so it seems equally plausible that 
> you'd want to do it using PL/pgSQL. Each of these two alternatives, inspired 
> by the advice that I got in this thread, works and produces the expected 
> output:
> 
> Yes, this works. This syntax is not ambiguous.
> 
> do $body$
> declare
>   r record;
> begin
>   select ((b, t)).*
>   into r
>   from tab1
>   where k = 1;
>   raise info 'Alt 1: % | %', r.f1::text, r.f2::text;
> 
>   r := (
>     select (b, t)
>     from tab1
>     where k = 1);
>   raise info 'Alt 2: % | %', r.f1::text, r.f2::text;
> end;
> $body$;
> 
> It feels a smidge uncomfortable because I'm forced to use reference by field 
> position (f1, f2) rather than by field name (b, t). But reference by position 
> is commonplace in PostgreSQL (for example, in the PREPARE statement). So 
> I'spose that I have to learn to like it.
> 
> postgres=# do $$
> declare r record;
> begin
>   select 10 as a, 20 as b into r;
>   raise notice '% %', r.a, r.b;
> end;
> $$;
> NOTICE:  10 20
> DO
> 
> The composite value always has structure, and types, but sometimes it can 
> lose labels. You can push labels by casting
> 
> r := (select (b, t) -- this is dynamic composity value, but without labels - 
> the scalar value doesn't hold label
> 
> or
> 
> r := (select (b, t)::type1 -- it is composite with labels again

Thanks, but I don't understand your "r := (select (b, t)::type1 -- it is 
composite with labels again". I tried this:

create procedure p(i in int)
  language plpgsql
as $body$
declare
  r record;
begin
  case i
    when 1 then
      select (b, t)::type1
      into r
      from tab1
      where k = 1;

    when 2 then
      r := (
        select (b, t)::type1
        from tab1
        where k = 1);

    else null;
  end case;
end;
$body$;

call p(3);
call p(2);
call p(1);

My idea with using a procedure and choosing which code path is followed at 
run-time is to distinguish between compile-time errors (there are none here) 
and run-time errors. Of course, "call p(3)" finishes with no error.

But both the other calls cause the same error:

42846: cannot cast type record to type1

But you say that this should work!


Reply via email to