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

jian he <jian.universality@gmail.com>

From: jian he <jian.universality@gmail.com>
To: Corey Huinker <corey.huinker@gmail.com>
Cc: Vik Fearing <vik@postgresfriends.org>, Isaac Morland <isaac.morland@gmail.com>, pgsql-hackers@lists.postgresql.org
Date: 2025-12-09T03:39:11Z
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

On Mon, Dec 1, 2025 at 1:41 PM Corey Huinker <corey.huinker@gmail.com> wrote:
>>
>> >> I'm fine with it. I can see having 'f' and 's' both mean cast functions, but 's' means safe, but the extra boolean works too and we'll be fine with either method.
>> >
>> >
>> > I can work on this part if you don't have time.
>>
>> Do you mean change pg_cast.casterrorsafe from boolean to char?
>
>
> No, I meant implementing the syntax for being able to declare a custom CAST function as safe (or not). Basically adding the [SAFE] to
>
> CREATE CAST (source_type AS target_type)
>     WITH [SAFE] FUNCTION function_name [ (argument_type [, ...]) ]
>
> I'm not tied to this syntax choice, but this one seemed the most obvious and least invasive.
>

hi.
In v14, I have removed pg_cast.casterrorsafe, but for user-defined CREATE CAST,
castfunc can be built-in function or user-defined function, we do need a way to
distinguish if the cast function is error safe or not.

I’ll incorporate pg_cast.casterrorsafe along with the implementation of the
user-defined CREATE CAST syntax into one patch.

> But this brings up an interesting point: if a cast is declared as WITHOUT FUNCTION aka COERCION_METHOD_BINARY, then the cast can never fail, and we should probably check for that because a cast that cannot fail can ignore the DEFAULT clause altogether and fall back to being an ordinary CAST().
>
>>

integer and oid are binary coercible, but the following should fail.
SELECT CAST(11 as oid DEFAULT 'a' ON CONVERSION ERROR);

if you mean that skip
+ ExecInitExprRec((Expr *) stcstate->stcexpr->default_expr,
+ state, resv, resnull);
For binary-coercible types, this approach seems fine. We’ve done something
similar in ExecInitExprRec for T_ArrayCoerceExpr.
```
                if (elemstate->steps_len == 1 &&
                    elemstate->steps[0].opcode == EEOP_CASE_TESTVAL)
                {
                    /* Trivial, so we need no per-element work at runtime */
                    elemstate = NULL;
                }
```
in V14, I didn't do this part, I'll keep this in mind.


--
jian
https://www.enterprisedb.com/