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

From: jian he <jian(dot)universality(at)gmail(dot)com>
To: Corey Huinker <corey(dot)huinker(at)gmail(dot)com>
Cc: Henson Choi <assam258(at)gmail(dot)com>, Peter <peter(at)eisentraut(dot)org>, Vik Fearing <vik(at)postgresfriends(dot)org>, Amul Sul <sulamul(at)gmail(dot)com>, Kirill Reshke <reshkekirill(at)gmail(dot)com>, Isaac Morland <isaac(dot)morland(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: CAST(... ON DEFAULT) - WIP build on top of Error-Safe User Functions
Date: 2026-10-30 01:54:11
Message-ID: CACJufxG8U4_+C-Hsr=pDs3wE1rK1mjdzoON8MPMFi0x8XwShYQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Wed, Oct 14, 2026 at 12:38 PM Corey Huinker <corey(dot)huinker(at)gmail(dot)com> wrote:
>> 4. extensive changes in clauses.c also required.
>>
>> Rationale:
>> CAST(('abc'::text)::int + abs(NULL) AS int DEFAULT 3 ON CONVERSION ERROR)
>>
>> To make the above query does not fail, which is what we want (at least, I think
>> so), we need to make evaluate_expr handle soft errors.
>> This means evaluate_expr needs an ErrorSaveContext node. As a result, we’ll need
>> to refactor every occurrence of ece_evaluate_expr.
>
> I disagree on this point. I believe that the leading a_expr
>
> ('abc'::text)::int
>
> should fail. We're looking for conversion errors on the cast operation itself, not before.
>

CREATE DOMAIN d_nota AS text CHECK (VALUE <> 'a');

> +SELECT CAST (CAST(a AS d_nota) AS text DEFAULT NULL ON CONVERSION ERROR) FROM tcast1;
> + a
> +---
> +
> +(1 row)
> +
> +SELECT CAST (CAST('a' AS d_nota) AS text DEFAULT NULL ON CONVERSION ERROR) FROM tcast1;
> + text
> +------
> +
> +(1 row)
>
> These should be failures at the inner cast level, before the on-conversion cast is attempted.
>
> Overall
> ======
>
> I'm concerned about the d_nota cast results as well as the no-subquery in the default expression limitation, but everything else is looking pretty good.
>

Previously I am using EXPR_KIND_TYPECAST_DEFAULT. After removing
EXPR_KIND_TYPECAST_DEFAULT, DEFAULT expressions can now include aggregates,
window functions, or subqueries, but expression return sets are still not
supported.
--------------------------

SELECT CAST(ARRAY[a, '7'] AS int[] DEFAULT '{1}' ON CONVERSION ERROR)
FROM (VALUES('a'), ('1')) t(a); -- QueryA
SELECT CAST(ARRAY[a::int] AS int[] DEFAULT NULL ON CONVERSION ERROR)
FROM (VALUES('a'), ('1')) t(a); -- QueryB

We want the QueryA to fail and QueryB not to. It is not trivial to do that.

transformArrayExpr has to transform each element of the ARRAY
constructor (ARRAY[expr]) the
same way as a non-array argument: the element expression itself is evaluated
normally, and only its conversion to the target element type is error-safe. The
result is an ArrayExpr whose element conversions report into the cast's
ErrorSaveContext, so that ArrayExpr must be evaluated under that context.
Otherwise the conversions cannot fail softly.

However, always evaluating SafeTypeCastExpr->arg under the cast's
ErrorSaveContext would make the source expression error-safe as well, so that

CAST(('abc'::text)::int AS int DEFAULT 3 ON CONVERSION ERROR)
would return 3 instead of failing.

For SafeTypeCastExpr->arg, the escontext needs to be passed down to
arg only when arg is an ARRAY constructor (ARRAY[expr]), not for any
other expression type.
Hence add a boolean field arg_errorsafe to SafeTypeCastExpr to record this.

I've attached inconsistency.sql; let me know which SQL query output is
unexpected.

> It may be worth thinking about whether the SAFE/UNSAFE function designation has utility outside of cast-default, as that may be committable independent of the cast changes.
I do not fully understand this part.
Can you expand on this?

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

Attachment Content-Type Size
inconsistency.sql application/sql 7.3 KB
v34-0003-CAST-expr-AS-newtype-DEFAULT-expr-ON-CONVERSION-ERROR.patch text/x-patch 162.7 KB
v34-0001-error-safe-for-casting-text-to-other-types-per-pg_cast.patch text/x-patch 9.3 KB
v34-0002-introduce-pg_proc.proerrorsafe.patch text/x-patch 67.0 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Ayoub Kazar 2026-10-30 01:57:21 Re: O(N^3) planning time in choose_plan_name() since 8c49a484e8e
Previous Message Tom Lane 2026-10-30 01:29:08 Re: Return INT_MAX or INT_MIN from strtoint() on overflow