Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vIg7w-009rEk-0D for pgsql-hackers@arkaria.postgresql.org; Tue, 11 Nov 2025 04:37:07 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vIg7t-004Fea-2H for pgsql-hackers@arkaria.postgresql.org; Tue, 11 Nov 2025 04:37:05 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vIg7t-004FeS-0s for pgsql-hackers@lists.postgresql.org; Tue, 11 Nov 2025 04:37:05 +0000 Received: from mail-il1-x135.google.com ([2607:f8b0:4864:20::135]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.96) (envelope-from ) id 1vIg7r-006UQ5-0P for pgsql-hackers@lists.postgresql.org; Tue, 11 Nov 2025 04:37:04 +0000 Received: by mail-il1-x135.google.com with SMTP id e9e14a558f8ab-4336f8e97c3so28914405ab.3 for ; Mon, 10 Nov 2025 20:37:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1762835822; x=1763440622; darn=lists.postgresql.org; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=F++oblCPqE2VPjjh2A5LIupyTw/J6L2ePh8/EQzjkrA=; b=Uf5OFopVDpdzGwY4Cua2WG3ch7XY1g78snCLjlG4PiEQ8VqVtmol0hHj0KGGMKdvFL WyGrGSgjUPTHP6uwPx967ULbguZLqgUKljHa/v2HmGPbSGJ9YPFpGWJbIsntlX2mroUb NiPZbA1aIlqVfqRuE6FBJZw/zgxyKIWT6OBD5QRkF98VKsMdMGcTt6pGnLkmbxteHdbM PQAA+mVL3tFVFquKOCBpIvxP8oLcoSlvueUEJOz3L7Dp7bja0J/y2mmhXDBx2C9ujQl0 +hfu12U1P+lHFjhP6CRgNyRzXhoecpSyQyCKJ+b/FeE9J95dR8bSLk1wEZjqWxp+Xrd6 de5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1762835822; x=1763440622; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=F++oblCPqE2VPjjh2A5LIupyTw/J6L2ePh8/EQzjkrA=; b=czL3h194f8LKV5e6sqniBpQmGPNjzfEwu0y//esgf6eY0Hfbbd4VAGZbu1JYEvA0xl MOLZKQd4DEQ4oSzr7RR/V5GoDrITKwzZIvc9E1fk7d6wX6WaDlFlWmC9bCZpoETV1xkS E2Nm/rluuEsxIKCD6/ENNyXFDKjE9x7MR27ho/3O1uq1+LfurxnD1yUyxm4WvJyvZ+ko vd/vVw7pCVLh87rGjtCbZtOg2Fv755ifhfmO/yjy3I1T6a9XmVmtzjEJc7mDxS7SvxzQ 2N96YcBnD4P0ByitOW9kzK/A8KNr7gIScbWcl943bcrMy4oE4wlV9uHiVfdXwIPgTE7f ea8A== X-Forwarded-Encrypted: i=1; AJvYcCU7NsQtt+78BBq2pJz738SszaofTahI6zXr0kEtimn4Lxqu0SI8CCFfmAQPWbC5P90XYf86h6z1tVvrUEfn@lists.postgresql.org X-Gm-Message-State: AOJu0YzT9Yo7PCJkR2ofevLYOirnIONJTij7DlrWdGF4XMWeLVkLa/c4 UfpbzgohHLaDCihy4mFxBA+tPceK73mLr0LDk96QyVeXczEWLFRX+QdsApbKxPHZqNKFtcI+GMp smhHw688px0Iwm67Yo5jr8S0l68ZoMp4= X-Gm-Gg: ASbGncuc2bHkKJ/HX3FcKDvBl4Upt2e1e7KAdokfYiI2ZDPXsZiYCof0EBuIDZlBga6 ibLaxZWqgCoHJHYbjedAAvFyMh29/8qTNHhlShqmmNfVTbBxqJwz+bNtH5B9nUZrHOR3wl59qOU PuhzU+dETEakWuSMzutJfUSed9BpKpDt7quF2vJ+ezDttseXdEEOSdTLsNwPM4RbGJw15gI63zQ gwFL129KYx6n/v6MNykmbnbDkDiNqpxCh/5pbkH+PN4P8nlwo++DMsxv0oU X-Google-Smtp-Source: AGHT+IH6yYsNR2L06TjbfvKiBkuBQwhuOwRUXa2PrFt/wUFRwqFPVO4duAfGKGL+V/02HGcMl454Sq/d59tzJEQDhPQ= X-Received: by 2002:a05:6e02:1806:b0:433:2aac:c540 with SMTP id e9e14a558f8ab-43367e18287mr170169565ab.14.1762835822283; Mon, 10 Nov 2025 20:37:02 -0800 (PST) MIME-Version: 1.0 References: <04afcd1f-ed7d-4c0a-add1-50e3719ccbf9@postgresfriends.org> <762ae707-7fdc-43d8-a77a-3a10d12ce21d@postgresfriends.org> In-Reply-To: From: Corey Huinker Date: Mon, 10 Nov 2025 23:36:49 -0500 X-Gm-Features: AWmQ_bnCtDYTd2oH5rqGyHCOXx-1u1vIVuq-SOYy36mhOZBqBEYn7vpOiOhes4o Message-ID: Subject: Re: CAST(... ON DEFAULT) - WIP build on top of Error-Safe User Functions To: jian he Cc: Vik Fearing , Isaac Morland , pgsql-hackers@lists.postgresql.org Content-Type: multipart/alternative; boundary="000000000000fc10fc06434a32d8" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --000000000000fc10fc06434a32d8 Content-Type: text/plain; charset="UTF-8" > > As mentioned before, to make > CAST(source_expr AS target_type DEFAULT expr ON CONVERSION ERROR); > work, > we cannot just simply replace casting FuncExpr nodes with CoerceViaIO, > since > type modifiers behave differently in these two Nodes. > (e.g., casting numeric 1.11 to integer is not equivalent to casting the > literal > "1.11" to integer). > I wasn't suggesting that. I was suggesting that we move tests that use a given type's custom cast function into the same patch that makes that cast safe. This would mean that the initial syntax+nodes+executor patch starts out only with test cases known to not have custom functions. > > Also, are we settled on this new pg_cast column name > (pg_cast.casterrorsafe)? > Overall, I think it's better not to touch pg_cast.dat in each of these > refactoring patches. > 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. > > Without first refactoring pg_cast.castfunc (01 to 18), making CAST ... > DEFAULT as the first patch (0001) > won't work, since pg_cast.castfunc itself is not error safe yet, and we > have no way to test the CAST DEFAULT syntax. > > So we have to *first* refactor pg_cast.castfunc, make it error safe > then implement CAST DEFAULT. > Makes sense. > > However, I found out, to make > SELECT CAST('five'::INTEGER AS INTEGER DEFAULT 6 ON CONVERSION ERROR); > error safe is hard. > That's no problem at all. The CAST () function can't do anything about an input that's already an error before the CAST node executes. Nor should it. It should only concern itself with errors related to the actual casting of a value to the specified type. > > ('five'::INTEGER) is a TypeCast node, normally it will error out in > transformTypeCast-> > coerce_to_target_type->coerce_type ```(if (inputTypeId == UNKNOWNOID > && IsA(node, Const)))``` > If we do not error out, then we need a Node to represent the failed cast, > mainly > for deparse purposes. > We _must_ error out in that case, before the CAST executes. > > that means for CAST(source_expr .... DEFAULT defexpr ON CONVERSION ERROR); > The only corner case we handle is when source_expr is a simple Const node. > In all other cases, source_expr is processed through transformExpr, > which does all > the normal parse analysis for a node. > I'll get to reviewing this patchset soon. --000000000000fc10fc06434a32d8 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
As mentioned before, to make
CAST(source_expr AS target_type DEFAULT expr ON CONVERSION ERROR);
work,
we cannot just simply replace casting FuncExpr nodes with CoerceViaIO, sinc= e
type modifiers behave differently in these two Nodes.
(e.g., casting numeric 1.11 to integer is not equivalent to casting the lit= eral
"1.11" to integer).

I wasn= 9;t suggesting that. I was suggesting that we move tests that use a given t= ype's=C2=A0custom cast function into the same patch that makes that cas= t safe. This would mean that the initial syntax+nodes+executor patch starts= out only with test cases known to not have custom functions.
=C2=A0

Also, are we settled on this new pg_cast column name (pg_cast.casterrorsafe= )?
Overall, I think it's better not to touch pg_cast.dat in each of these<= br> refactoring patches.

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 b= e fine with either method.
=C2=A0

Without first refactoring pg_cast.castfunc (01 to 18), making CAST ...
DEFAULT as the first patch (0001)
won't work, since pg_cast.castfunc itself is not error safe yet, and we=
have no way to test the CAST DEFAULT syntax.

So we have to *first* refactor pg_cast.castfunc, make it error safe
then implement CAST DEFAULT.

Makes sens= e.
=C2=A0
=
However, I found out, to make
SELECT CAST('five'::INTEGER AS INTEGER DEFAULT 6 ON CONVERSION ERRO= R);
error safe is hard.

That's no probl= em at all. The CAST () function can't do anything about an input that&#= 39;s already an error before the CAST node executes. Nor should it. It shou= ld only concern itself with errors related to the actual casting of a value= to the specified type.
=C2=A0

('five'::INTEGER) is a TypeCast node, normally it will error out in=
transformTypeCast->
coerce_to_target_type->coerce_type ```(if (inputTypeId =3D=3D UNKNOWNOID=
&& IsA(node, Const)))```
If we do not error out, then we need a Node to represent the failed cast, m= ainly
for deparse purposes.

We _must_ error o= ut in that case, before the CAST executes.
=C2=A0

that means for CAST(source_expr .... DEFAULT defexpr ON CONVERSION ERROR);<= br> The only corner case we handle is when source_expr is a simple Const node.<= br> In all other cases, source_expr is processed through transformExpr,
which does all
the normal parse analysis for a node.

I= 'll get to reviewing this patchset soon.
--000000000000fc10fc06434a32d8--