Re: CAST(... ON DEFAULT) - WIP build on top of Error-Safe User Functions

Corey Huinker <corey.huinker@gmail.com>

From: Corey Huinker <corey.huinker@gmail.com>
To: jian he <jian.universality@gmail.com>
Cc: Vik Fearing <vik@postgresfriends.org>, Isaac Morland <isaac.morland@gmail.com>, pgsql-hackers@lists.postgresql.org
Date: 2025-08-04T05:09:21Z
Lists: pgsql-hackers

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Make cast functions to type money error safe

  2. Make cast function from circle to polygon error safe

  3. Make geometry cast functions error safe

  4. Make cast functions from jsonb error safe

  5. Make many cast functions error safe

  6. Add SQL/JSON query functions

  7. Add soft error handling to some expression nodes

>
> so we need to handle numeric source types with fractional points with
> special care.
> currently, this applies only to numeric, float4, and float8.
> (hope this is all the corner case we need to catch...)
>

I'm fairly certain that the committers won't like us special-casing the
internal cast functions, as we would have to maintain these special cases
as new core types are added, and it still bypasses the defined cast
function for user-defined types, which could have similar issues similar to
the rounding issue.

I think the way forward here is either to:

1.  add a second function definition to CAST. The potential syntax forr a
second function gets clumsy, but might look something like this:

CREATE CAST (source_type AS target_type)
    WITH FUNCTION function_name [ (argument_type [, ...]) ]
    [ AS ASSIGNMENT | AS IMPLICIT ]
   [
    WITH SAFE FUNCTION function_name [ (argument_type [, ...]) ]
    [ AS ASSIGNMENT | AS IMPLICIT ]
   ]

That doesn't seem right to me, it seems easier to:

2. Modify the CAST definition to indicate whether the existing cast
function has the regular function signature or a -Safe one. In cases where
a CAST has a defined function but the safe flag is turned off, we would
have to fail the query with an error like "Defined CAST function from
srctype to desttype is not error-safe".

This would involve changing the syntax of CREATE CAST by adding an option
SAFE, or ERROR SAFE, or similar:

CREATE CAST (source_type AS target_type)
    WITH [SAFE] FUNCTION function_name [ (argument_type [, ...]) ]
    [ AS ASSIGNMENT | AS IMPLICIT ]

We would add a new value to pg_cast.castmethod, 's' for "safe".

We could refactor all the numeric types to use the modified functions, so
no special-case code there anymore, and it gives extension writers an
incentive to (eventually) make their own cast functions error-safe.

While method 2 seems a lot cleaner, there may be a performance regression
in the now error-safe typecast functions. If so, that might tip the balance
to having two functions defined.