On Thu, Jul 2, 2026 at 10:06 PM Henson Choi <[email protected]> wrote:
>>
>>
>> E. User-defined types reached via I/O coercion: reject, or support?
>>
>> The documentation says only built-in casts are supported, and a
>> user-defined WITH FUNCTION cast is rejected at parse time:
>>
>> CREATE FUNCTION int_to_point(int) RETURNS point
>> AS 'SELECT point($1, $1)' LANGUAGE sql IMMUTABLE;
>> CREATE CAST (int AS point) WITH FUNCTION int_to_point(int);
>> SELECT CAST(1 AS point DEFAULT NULL ON CONVERSION ERROR);
>> -- ERROR: cannot cast type integer to point with DEFAULT expression
>> -- in CAST ... ON CONVERSION ERROR
>> -- DETAIL: Safe type casts for user-defined types are not yet supported.
>>
>> But a user-defined type reached through I/O coercion (a WITH INOUT
>> cast, or a plain text->type explicit cast) is accepted, and a
>> hard-erroring input function then leaks straight through
>> ON CONVERSION ERROR instead of being rejected or folding into the
>> DEFAULT. widget_in/widget_out below are the deliberately hard-erroring
>> I/O functions from the regression suite (src/test/regress/regress.c),
>> with :regresslib set to the regression shared library as in
>> test_setup.sql:
>>
>> CREATE TYPE hardtype;
>> CREATE FUNCTION hardtype_in(cstring) RETURNS hardtype
>> AS :'regresslib', 'widget_in' LANGUAGE C STRICT IMMUTABLE;
>> CREATE FUNCTION hardtype_out(hardtype) RETURNS cstring
>> AS :'regresslib', 'widget_out' LANGUAGE C STRICT IMMUTABLE;
>> CREATE TYPE hardtype (internallength = 24, input = hardtype_in,
>> output = hardtype_out, alignment = double);
>> CREATE CAST (text AS hardtype) WITH INOUT;
>>
>> SELECT CAST('bad'::text AS hardtype DEFAULT NULL ON CONVERSION ERROR);
>> -- ERROR: invalid input syntax for type widget: "bad" (leaked, not
>> DEFAULT/NULL;
>> -- the error says "widget" because the reused widget_in reports its
>> own name)
>>
>> So the "not supported" rule is enforced for one path but not the other.
>>
But src/test/regress/regress.c have below comments:
/*
* Note: DON'T convert this error to "soft" style (errsave/ereturn). We
* want this data type to stay permanently in the hard-error world so that
* it can be used for testing that such cases still work reasonably.
*/
That means
SELECT CAST('bad'::text AS hardtype DEFAULT NULL ON CONVERSION ERROR);
is bound to error out.
SELECT pg_input_is_valid('bad', 'widget');
will also error out.
User-defined types coerced through I/O functions are assumed to be error-safe.
If the input function is implemented to support error-safe execution, the
coercion can also be evaluated in an error-safe manner; see EEOP_IOCOERCE_SAFE.
That's our current status, so I don't think we need to do anything special.
----------------------------------------------------------------------------------------------------
Since not all functions support error-safe execution, scenario A is
unavoidable. Scenarios C and D are explained in [1], while scenario B
mentioned in [2] is a bug.
[1]
https://www.postgresql.org/message-id/CACJufxEawrK%2BFhFzyWMPKZ_r11jEqbzq4soUM2ZRBNSintQ%2BAQ%40mail.gmail.com
[2]
https://www.postgresql.org/message-id/CAAAe_zDMjcFgZJoS%3DzQn5VdetZ5qQcoHiZmLriAdrYLGPTsPZg%40mail.gmail.com
--
jian
https://www.enterprisedb.com/