resolve_generic_type() is over-complex and under-correct - Mailing list pgsql-hackers

From Tom Lane
Subject resolve_generic_type() is over-complex and under-correct
Date
Msg-id 6093.1584202130@sss.pgh.pa.us
Whole thread Raw
List pgsql-hackers
parse_coerce.c's resolve_generic_type() is written on the assumption
that it might be asked to infer any polymorphic type's concrete type
given any other polymorphic type's concrete type.  This is overkill,
because the only call sites look like

        anyelement_type = resolve_generic_type(ANYELEMENTOID,
                                               anyarray_type,
                                               ANYARRAYOID);

        subtype = resolve_generic_type(ANYELEMENTOID,
                                       anyrange_type,
                                       ANYRANGEOID);

        anyarray_type = resolve_generic_type(ANYARRAYOID,
                                             anyelement_type,
                                             ANYELEMENTOID);

(There are two occurrences of each of these in funcapi.c,
and nothing anywhere else.)

But that's a good thing, because resolve_generic_type() gets some
of the un-exercised cases wrong.  Notably, it appears to believe
that anyrange is the same type variable as anyelement: if asked
to resolve anyarray from anyrange, it will produce the array over
the concrete range type, where it should produce the array over
the range's subtype.

Rather than fix this up, I'm inclined to just nuke resolve_generic_type()
altogether, and replace the call sites with direct uses of the underlying
lookups such as get_array_type().  I think this is simpler to understand
as well as being significantly less code.

I also noticed that there's an asymmetry in funcapi.c's usage pattern:
it can resolve anyelement from either anyarray or anyrange, but it
can only resolve anyarray from anyelement not anyrange.  This results
in warts like so:

regression=# create function foo(x anyrange) returns anyarray language sql
as 'select array[lower(x),upper(x)]';
CREATE FUNCTION
regression=# select foo(int4range(6,9));
  foo
-------
 {6,9}
(1 row)

-- so far so good, but let's try it with OUT parameters:

regression=# create function foo2(x anyrange, out lu anyarray, out ul anyarray)
language sql
as 'select array[lower(x),upper(x)], array[upper(x),lower(x)]';
CREATE FUNCTION
regression=# select * from foo2(int4range(6,9));
ERROR:  cache lookup failed for type 0

So that's a bug that needs fixing in any case.

            regards, tom lane



pgsql-hackers by date:

Previous
From: James Coleman
Date:
Subject: Re: [PATCH] Incremental sort (was: PoC: Partial sort)
Next
From: James Coleman
Date:
Subject: Re: [PATCH] Incremental sort (was: PoC: Partial sort)