| From: | Kirill Reshke <reshkekirill(at)gmail(dot)com> |
|---|---|
| To: | imchifan(at)mail(dot)com, pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Subject: | Re: BUG #19862: Replacing a cast leaves prepared statements using the old cast function |
| Date: | 2026-11-11 12:56:05 |
| Message-ID: | CALdSSPhVWsPLi4r6NBk8kAsxdhPfZE+v7LHu9YpsHrk0_HFg1w@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
On Wed, 11 Nov 2026 at 15:32, PG Bug reporting form
<noreply(at)postgresql(dot)org> wrote:
>
> The following bug has been logged on the website:
>
> Bug reference: 19862
> Logged by: Faye
> Email address: imchifan(at)mail(dot)com
> PostgreSQL version: Unsupported/Unknown
> Operating system: Linux/amd64
> Description:
>
> Dropping and recreating a user-defined cast with a different cast function
> does not invalidate a statement prepared while the original cast existed.
> After the replacement, direct execution uses the new function and returns
> v2, while the prepared statement silently continues to use the old function
> and returns v1.
>
> The prepared statement should use the current cast definition, as direct
> execution does. Both executions should therefore return v2 after the cast is
> replaced.
>
> How to repeat:
>
> \set ON_ERROR_STOP on
>
> DROP TYPE IF EXISTS cast_src CASCADE;
> DROP TYPE IF EXISTS cast_dst CASCADE;
>
> CREATE TYPE cast_src AS ENUM ('x');
> CREATE TYPE cast_dst AS ENUM ('v1', 'v2');
>
> CREATE FUNCTION cast_v1(cast_src)
> RETURNS cast_dst
> LANGUAGE SQL IMMUTABLE
> AS $$ SELECT 'v1'::cast_dst $$;
>
> CREATE FUNCTION cast_v2(cast_src)
> RETURNS cast_dst
> LANGUAGE SQL IMMUTABLE
> AS $$ SELECT 'v2'::cast_dst $$;
>
> CREATE CAST (cast_src AS cast_dst)
> WITH FUNCTION cast_v1(cast_src);
>
> PREPARE cast_stmt(cast_src) AS
> SELECT $1::cast_dst AS value;
>
> EXECUTE cast_stmt('x') \gset before_
>
> DROP CAST (cast_src AS cast_dst);
> CREATE CAST (cast_src AS cast_dst)
> WITH FUNCTION cast_v2(cast_src);
>
> SELECT ('x'::cast_src)::cast_dst AS value \gset direct_
> EXECUTE cast_stmt('x') \gset prepared_
>
> SELECT :'before_value' AS initial_prepared_value,
> :'direct_value' AS direct_value_after_cast_replacement,
> :'prepared_value' AS prepared_value_after_cast_replacement,
> :'direct_value' = :'prepared_value' AS prepared_matches_direct;
>
> DEALLOCATE cast_stmt;
> DROP CAST (cast_src AS cast_dst);
> DROP FUNCTION cast_v1(cast_src);
> DROP FUNCTION cast_v2(cast_src);
> DROP TYPE cast_src;
> DROP TYPE cast_dst;
>
> The recorded result is:
>
> initial_prepared_value | direct_value_after_cast_replacement |
> prepared_value_after_cast_replacement | prepared_matches_direct
> ------------------------+-------------------------------------+---------------------------------------+-------------------------
> v1 | v2 | v1
> | f
> (1 row)
>
> This is consistent with parse analysis retaining the originally selected
> cast function without invalidating the prepared statement when the cast
> catalog entry changes.
>
> The issue was reproduced on PostgreSQL 20devel. It was also reproduced
> separately on PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2). Both environments
> were Linux/amd64. No server interruption or server-log error occurred. This
> occurs when a user-defined cast is replaced with one backed by a different
> function after a statement using that cast has been prepared.
>
Hi! Yes, reproduced cast issue here. I also reported something similar
here[0]. There are some more catalog objects which miss catalog
invalidate hooks. Among those, there are 6 types of objects for which
object altering can make cached plan wrong:
CASTSOURCETARGET
AMPROCNUM
COLLOID
TSCONFIGOID
TSCONFIGMAP
TSDICTOID
Patch contains only these six fixes. In v2-0002 there are examples on
how to make cached plan to behave wrong for each object type. It is
not intended to commit.
--
Best regards,
Kirill Reshke
| Attachment | Content-Type | Size |
|---|---|---|
| v2-0001-Invalidate-plans-after-catalog-changes.patch | application/octet-stream | 1.5 KB |
| v2-0002-Test-plan-invalidation-after-catalog-changes.patch | application/octet-stream | 18.1 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Heikki Linnakangas | 2026-11-11 12:58:48 | Re: BUG #19862: Replacing a cast leaves prepared statements using the old cast function |
| Previous Message | Dean Rasheed | 2026-11-11 12:33:45 | Re: BUG #19802: MERGE into a partitioned table fails with "SubPlan found with no parent plan" |