Thread

Commits

  1. Restructure polymorphic-type resolution in funcapi.c.

  1. resolve_generic_type() is over-complex and under-correct

    Tom Lane <tgl@sss.pgh.pa.us> — 2020-03-14T16:08:50Z

    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