Re: Support prepared statement invalidation when result types change - Mailing list pgsql-hackers
From | jian he |
---|---|
Subject | Re: Support prepared statement invalidation when result types change |
Date | |
Msg-id | CACJufxFOdg==w4e+YnNra2fK5A7YqmLynYB2qV5Ty=Emjb6u4w@mail.gmail.com Whole thread Raw |
In response to | Support prepared statement invalidation when result types change (Jelte Fennema <me@jeltef.nl>) |
Responses |
Re: Support prepared statement invalidation when result types change
|
List | pgsql-hackers |
On Sat, Aug 26, 2023 at 1:58 AM Jelte Fennema <me@jeltef.nl> wrote: > > The cached plan for a prepared statements can get invalidated when DDL > changes the tables used in the query, or when search_path changes. When > this happens the prepared statement can still be executed, but it will > be replanned in the new context. This means that the prepared statement > will do something different e.g. in case of search_path changes it will > select data from a completely different table. This won't throw an > error, because it is considered the responsibility of the operator and > query writers that the query will still do the intended thing. > > However, we would throw an error if the the result of the query is of a > different type than it was before: > ERROR: cached plan must not change result type > > This requirement was not documented anywhere and it > can thus be a surprising error to hit. But it's actually not needed for > this to be an error, as long as we send the correct RowDescription there > does not have to be a problem for clients when the result types or > column counts change. > > This patch starts to allow a prepared statement to continue to work even > when the result type changes. > > Without this change all clients that automatically prepare queries as a > performance optimization will need to handle or avoid the error somehow, > often resulting in deallocating and re-preparing queries when its > usually not necessary. With this change connection poolers can also > safely prepare the same query only once on a connection and share this > one prepared query across clients that prepared that exact same query. > > Some relevant previous discussions: > [1]: https://www.postgresql.org/message-id/flat/CAB%3DJe-GQOW7kU9Hn3AqP1vhaZg_wE9Lz6F4jSp-7cm9_M6DyVA%40mail.gmail.com > [2]: https://stackoverflow.com/questions/2783813/postgres-error-cached-plan-must-not-change-result-type > [3]: https://stackoverflow.com/questions/42119365/how-to-avoid-cached-plan-must-not-change-result-type-error > [4]: https://github.com/pgjdbc/pgjdbc/pull/451 > [5]: https://github.com/pgbouncer/pgbouncer/pull/845#discussion_r1305295551 > [6]: https://github.com/jackc/pgx/issues/927 > [7]: https://elixirforum.com/t/postgrex-errors-with-cached-plan-must-not-change-result-type-during-migration/51235/2 > [8]: https://github.com/rails/rails/issues/12330 prepared statement with no parameters, tested many cases (add column, change column data type, rename column, set default, set not null), it worked as expected. With parameters, it also works, only a tiny issue with error reporting. prepstmt2 | PREPARE prepstmt2(bigint) AS SELECT * FROM pcachetest WHERE q1 = $1; | {bigint} | {bigint,bigint,bigint} ERROR: column "q1" does not exist at character 61 HINT: Perhaps you meant to reference the column "pcachetest.x1". STATEMENT: execute prepstmt2(1); I think "character 61" refer to "PREPARE prepstmt2(bigint) AS SELECT * FROM pcachetest WHERE q1 = $1;" so maybe the STATEMENT is slightly misleading.
pgsql-hackers by date: