このリリースは 12.18 からの修正リリース(2024年 5月 9日リリース)です。
12.X からのアップデートではダンプ、リストアは不要です。
しかしながら、12.18 よりも前のバージョンからアップデートする場合には、12.18 のリリース情報も参照してください。
12.x バージョン系列は本リリースで最終リリースとなる予定です。
PostgreSQL 12.18 から 12.19 への変更点
16.3、15.7、14.12、13.15、12.19 の各バージョンが同時にリリースされており、本ページでは共通の記載としています。各修正項目が適用されるバージョン系列番号を項目末尾に括弧書きで記載しています。
- pg_stats_ext と pg_stats_ext_exprs の行の可視性がテーブル所有者だけに制限されました。(CVE-2024-4317) (Nathan Bossart) (16)(15)(14)
- 複数の VALUES 行からの INSERT で対象列が配列か複合型を元にしたドメイン型である場合について、修正されました。 (Tom Lane) (16)(15)(14)(13)(12)
- DO NOTHING を行う MERGE でも対象テーブルに SELECT 権限が必要になりました。 (Álvaro Herrera) (16)(15)
- MERGE による(UPDATE・DELETE アクションによる)自己書き換えタプルの処理が修正されました。 (Dean Rasheed) (16)(15)
- テーブルが boolean型の列でパーティショニングされていて、問い合わせが boolean型の「IS NOT」句を持つ場合の、誤った NULLパーティションのプルーニングが修正されました。 (David Rowley) (16)(15)(14)(13)(12)
- ALTER FOREIGN TABLE SET SCHEMA の実行で、所有されているシーケンスが新しいスキーマに移動するようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- ALTER TABLE ... ADD COLUMN の実行で、所有するテーブルと同じ永続性を持つ IDENTITY/シリアルシーケンスが作成されるようになりました。 (Peter Eisentraut) (16)(15)
- 従属関係を持つ関数またはパブリケーションが存在する場合に発生するALTER TABLE ... ALTER COLUMN TYPE のエラーメッセージが改善されました。 (Tom Lane) (16)(15)(14)
- CREATE DATABASE で、他のオプションとの一貫性を保つために、STRATEGY キーワードを大文字と小文字を区別せずに認識するようになりました。 (Tomas Vondra) (16)(15)
- Bitmap Heap Scan によってアクセスされたヒープページのEXPLAIN のカウントが修正されました。 (Melanie Plageman) (16)(15)(14)(13)(12)
- MERGE のサブプランに対する EXPLAIN 出力が修正されました。 (Dean Rasheed) (16)(15)
- 孤児になった一時テーブルを削除するときに起きるデッドロックを回避するようになりました。 (Mikhail Zhilin) (16)(15)(14)(13)(12)
- DISABLE_PAGE_SKIPPING オプションを使用した VACUUM での可視性マップ状態の更新が修正されました。 (Heikki Linnakangas) (16)
- リレーションごとの凍結XID値を検査する際に競合状態を回避するようになりました。 (Noah Misch) (16)(15)(14)(13)(12)
- 並列VACUUM処理のバッファ使用量レポートが修正されました。 (Anthonin Bonnefoy) (16)(15)
- プランナで、同値クラスから生成された結合条件が確実に正しい計画レベルに適用されるようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- ORDER BY または DISTINCTオプションを使用した集計関数の計画時に発生するエラー「ERROR: could not find pathkey item to sort」が修正されました。 (David Rowley) (16)
- 一部のウィンドウ関数への潜在的に間違った最適化が防止されました。 (David Rowley) (16)(15)
- 移動しないウィンドウフレームで移動集約モードを無駄に使用しないようになりました。 (Vallimaharajan G) (16)(15)(14)(13)(12)
- GEQO でパーティションごとの結合を計画する時に、解放済データの使用を避けるようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- Memoize で使用中のデータを解放しないようになりました。 (Tender Wang, Andrei Lepikhov) (16)(15)(14)
- 「ERROR: requested statistics kind "X" is not yet built」というメッセージで誤って報告されていた統計の種類コードが修正されました。 (David Rowley) (16)(15)(14)(13)(12)
- 「catcache list」オブジェクトを線形検索する代わりにハッシュテーブルを使用するようになりました。 (Tom Lane) (16)
- FROM で RECORD を返す関数についてより注意深い実装になりました。 (Tom Lane) (16)(15)(14)(13)(12)
- 行型を返す SQL言語プロシージャに関する混乱が修正されました。 (Tom Lane) (16)(15)(14)(13)(12)
- 内部実装のためのいくつかの再帰関数に保護的なスタック深さ検査が追加されました。 (Egor Chindyaskin) (16)(15)(14)(13)(12)
- date_bin() の丸めミスとオーバーフローの危険性が修正されました。 (Moaaz Assali) (16)(15)(14)
- timestamp型の値に interval型の値を足し引きするときに整数オーバーフローを検出するようになりました。 (Joseph Koshakow) (16)(15)(14)(13)(12)
- pg_get_expr() での競合状態を回避するようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- XIDステータス関数での古いトランザクションID の検出が修正されました。 (Karina Litskevich) (16)(15)(14)(13)(12)
- テーブルのフリースペースマップが、テーブルの終端を過ぎたページを返さないようになりました。 (Ronan Dunklau) (16)(15)(14)
- WaitEventSetWait で待機中にエラーが生じた場合の、ファイルディスクリプタのリークが修正されました。 (Etsuro Fujita) (16)(15)(14)(13)(12)
- 外部テーブルへの非同期 Append を伴う問い合わせで、例外スタックが壊れることがあり修正されました。 (Alexander Pyhalov) (16)(15)(14)
- インデックスの再作成中にインデックスにアクセスすると、エラーを出すようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- name型の列に対する Index Only Scan で、正しい値が返されるようになりました。 (David Rowley) (16)(15)(14)(13)(12)
- レプリケーションスロットの無効化時に生じる競合状態が修正されました。 (Bertrand Drouvot) (16)
- 論理レプリケーションでテーブル同期操作が必要かどうかを決定する際の競合状態が修正されました。 (Vignesh C) (16)(15)
- 4GB を超える DSM(動的共有メモリ)割り当てによるクラッシュが修正されました。 (Heikki Linnakangas) (16)(15)(14)(13)(12)
- 新しいサーバーセッションのクライアントソケットを非ブロッキングモードにできない場合は、そのセッションを切断するようになりました。 (Heikki Linnakangas) (16)(15)(14)(13)(12)
- OpenSSL 3.0.0 以降での不適切なエラー報告が修正されました。 (Heikki Linnakangas, Tom Lane) (16)(15)(14)(13)(12)
- Windows で API関数 getaddrinfo() のエラー報告処理のスレッドセーフ性が修正されました。 (Thomas Munro) (16)
- libpq と ecpglib が、Cライブラリ関数 bindtextdomain() への同時呼び出しを回避するようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- ecpg のプリプロセッサがクラッシュする問題が修正されました。 (Tom Lane) (16)(15)(14)(13)(12)
- ecpg が「unspported feature will be passed to server 」という誤った警告を出さないようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- ecpg を Infomix互換モードで実行したときに、追加される関数 intoasc() の結果文字列が正しくゼロ終端されるようになりました。 (Oleg Tselebrovskiy) (16)(15)(14)(13)(12)
- initdb の -c オプションでは、大文字と小文字を区別せずにパラメータ名を照合するようになりました。 (Tom Lane) (16)
- psql でクエリがキャンセルされた後にクエリ結果がリークしないようになりました。 (Tom Lane) (16)(15)
- ロールのコメントが存在する場合、 --no-role-passwords の設定に関係なく、ロールのコメントがダンプされるように pg_dumpall が修正されました。 (Daniel Gustafsson, Álvaro Herrera) (16)(15)(14)(13)(12)
- MacOS 上で、pg_basebackup、pg_checksums、および pg_rewind で .DS_Store という名前のファイルをスキップするようになりました。 (Daniel Gustafsson) (16)(15)
- PL/pgSQL の式に続く単一行コメント (「--」形式のコメント) の解析が修正されました。 (Erik Wienhold, Tom Lane) (16)(15)(14)(13)(12)
- contrib/amcheck で、短いヘッダ値と長いヘッダ値による誤った一致の失敗を報告しないようになりました。 (Andrey Borodin, Michael Zhilin) (16)(15)(14)(13)(12)
- BRIN 出力関数のバグが修正されました。 (Tomas Vondra) (16)(15)(14)
- contrib/postgres_fdw で、定数によるソート要求を発行しないようになりました。 (David Rowley) (16)(15)(14)(13)(12)
- contrib/postgres_fdw でリモートセッションのタイムゾーンを「UTC」ではなく「GMT」に設定するようになりました。 (Tom Lane) (16)(15)(14)(13)(12)
- contrib/xml2 において、最近の libxml2 のバージョンで非推奨となったライブラリ関数の使用を避けるようになりました。 (Dmitry Koval) (16)(15)(14)(13)(12)
- LLVM 18 との非互換性が修正されました。 (Thomas Munro, Dmitry Dolgov) (16)(15)(14)(13)(12)
- 「make check」が musl C ライブラリで動作できるようになりました。 (Thomas Munro, Bruce Momjian, Tom Lane) (16)(15)(14)(13)(12)
- CREATE RULE コマンドで、既にコマンド内の外側で使用されているテーブルをビューに変換することが禁止されました。 (Tom Lane) (15)(14)(13)(12)
これらのビューは、アクセスするユーザに読み取り権限の無い列を伴う式の統計情報を隠していませんでした。most_common_vals などのビュー列でデータ露出が生じていました。潜在的な影響は完全には明らかになっていないため、安全性の観点から、これらのビューは関連するテーブルの所有者にしか表示されないものとなりました。
この修正では、新たに initdb で作成されたデータベースクラスタにしか修正の影響が及びません。既存のデータベースクラスタに対して適用するには、以下の手順が必要です。
インストール先 share ディレクトリ下の fix-CVE-2024-4317.sql を スーパーユーザ(下記例では postgres)で各データベースに対して実行する。 $ psql -U postgres -d 《DB名》 -f "fix-CVE-2024-4317.sql" このとき template0 データベースも対象にする。 template0 に対して SQLスクリプトを実行するには、 以下のように一時的に接続を許可して行う。 $ psql -U postgres -c "ALTER DATABASE template0 WITH ALLOW_CONNECTIONS true;" $ psql -U postgres -d template0 -f "fix-CVE-2024-4317.sql" $ psql -U postgres -c "ALTER DATABASE template0 WITH ALLOW_CONNECTIONS false;"
このような場合に、予期せぬデータ型の不一致のエラーか、奇妙な INSERT結果(誤った問い合わせ結果)が生じることがありました。
(エラー発生例:1行 INSERT では成功するものが 2行 INSERT で失敗する) db1=# CREATE typ2 AS (e1 int, e2 text); db1=# CREATE DOMAIN dom2 AS typ2; db1=# CREATE TABLE t2 (c1 int, c2 dom2); db1=# INSERT INTO t2 (c2.e1, c2.e2) VALUES (1, 'A'); db1=# INSERT INTO t2 (c2.e1, c2.e2) VALUES (2, 'B'), (3, 'C'); ERROR: subfield "e1" is of type integer but expression is of type dom2
これにより特別なケースでの問題を回避します。「MERGE INTO t3 USING (SELECT 1) ON (true) WHEN MATCHED THEN DO NOTHING」のような形の問い合わせでアサート失敗が生じる場合が報告されました。仕様変更となりますが、実用的な MERGE文の動作に影響は無いと考えられます。
ターゲット行が 2行以上のソース行と結合する場合には、SQL標準に従って、エラーを出すようになりました。これまでの実装では同時更新を伴う場合に本条件を無視することがありました。
また、BEFOREトリガや VOLATILE の関数が問い合わせで使われていることで、ターゲット行が同トランザクションのコマンドで既に更新されていた場合に、誤解を招かないエラーメッセージを出すようになりました。
(新たに出るようになったエラーメッセージ) ERROR: tuple to be updated or deleted was already modified by an operation triggered by the current command HINT: Consider using an AFTER trigger instead of a BEFORE trigger to propagate changes to other rows.
「《NULL値》 IS NOT FALSE」のような条件に対して、予期せぬエラーや誤った問い合わせ結果が生じました。
(RANGE、HASHパーティションでは予期せぬエラーが発生) db1=# CREATE TABLE t5 (b boolean, i int) PARTITION BY RANGE (b, i); db1=# CREATE TABLE t5p PARTITION OF t5 FOR VALUES FROM (false, 0) TO (false, 1); db1=# SELECT * FROM t5 WHERE b IS NOT true; ERROR: invalid strategy number 0 (LISTパーティションの場合、NULLのパーティションが読み飛ばされる) db1=# CREATE TABLE t5l (b bool, i int) PARTITION BY LIST (b); db1=# CREATE TABLE t5lp PARTITION OF t5l FOR VALUES IN (NULL); db1=# INSERT INTO t5lp VALUES (NULL, 0); db1=# SELECT * FROM t5l WHERE b IS NOT true; b | i ---+--- (0 rows)
通常のテーブルを新しいスキーマに移動すると、そのテーブルが所有するシーケンスも(インデックスと制約とともに)そのスキーマに移動されます。 しかし、外部テーブルではこのシーケンスの移動が見落とされていました。
CREATE UNLOGGED TABLE を使用すると、所有されているシーケンスもWAL出力されなくなります。 ALTER TABLE はこの点を考慮していなかったため、追加された IDENTITY列はWAL記録されたシーケンスが含まれることになりますが、これは無意味であると判断されました。
db1=# CREATE TABLE t(a int); db1=# CREATE PUBLICATION p FOR TABLE t WHERE (a > 0); db1=# ALTER TABLE t ALTER COLUMN a TYPE bigint; (以前発生していたエラーメッセージ) ERROR: unexpected object depending on column: publication of table t in publication p (改善されたエラーメッセージ) ERROR: cannot alter type of a column used by a publication WHERE clause DETAIL: publication of table t in publication p depends on column "a"
以前は、可視タプルを含まないヒープページはカウントされていませんでしたが、Bitmap Index Scan によって返されるすべてのページをカウントする方がより一貫性があると判断されました。
プランツリーの他の部分にある変数を参照する SubPlan のパラメータが適切に表示されないことがありました。EXPLAIN出力中に問い合わせに含まれない ctid列が出現する誤動作が報告されました。
一時テーブルを作成するセッションがテーブルを削除せずにクラッシュした場合、自動バキュームが最終的に孤児テーブルを削除しようとします。 ただし、同じ一時名前空間が割り当てられているセッションでも同様に削除しようとします。一時テーブルに依存関係(所有シーケンスなど)がある場合、これら 2つのクリーンアップ試行の間でデッドロックが発生する可能性がありました。
このデッドロックは「ERROR: deadlock detected ...」エラーで検出されます。
見落としにより、この動作モードではすべてのヒープページがダーティになり、過剰な I/O が発生していました。また、誤って設定された可視性マップビットもクリアされませんでした。
VACUUM によるリレーションごとの値からのデータベースごとの凍結XID値の計算が、別の VACUUM によるこれらの値の同時更新によって混乱する可能性がありました。
並列ワーカによって実行されたバッファアクセスが VERBOSEモードで報告される統計にカウントされませんでした。
PostgreSQL 16 より前のバージョンでは、生成された条件が外部結合の上(後)で評価されるべき時に、外部結合の下で評価される可能性があり、誤った問い合わせ結果が発生する可能性がありました。一部の SELECTアームの結合列に定数出力を持つ UNION ALL ツリーへの結合を検討する場合には、16.x を含む全バージョンに同様の危険性がありました。
これは PostgreSQL 16.1 で適用された修正(31番の項目)に似ていますが、本修正では並列プランに対して問題解決します。
非定数引数を使用した ntile() および count() の Run Condition の最適化を無効にするようになりました。これにより副問合せで発生する可能性のある誤動作が回避されます。誤動作で典型的には「ERROR: WindowFunc not found in subplan target lists」のようなエラーが生じます。
通常の集約関数がウィンドウ関数として使用されて、ウィンドウフレームの開始が UNBOUNDED PRECEDING として指定されている場合、そのフレームの先頭位置は移動できないため、特別な (そしてより高価な) 移動集計モードを使用する必要はありません。この最適化は当初から意図されていましたが、コーディングエラーのために働いていませんでした。
通常これはクラッシュまたは予期せぬエラーメッセージを引き起こします。
運用ビルドでは、解放されたデータは使用前に上書きされない可能性が高いため、このエラーは頻繁には問題を引き起こしませんでした。潜在的にはクラッシュを引き起こす可能性があります。
エラー発生時に「X」部分が誤って出力されていました。
この変更により、何千ものロールを持つインストレーションにおけるいくつかの操作で報告された性能問題(GRANT ROLE で数十秒かかる等)が解決されます。
このような関数呼び出しの出力列は、列名とデータ型を指定する AS句によって定義する必要があります。実際の関数の出力値がそれと一致しない場合、実行時にエラーになるはずです。
しかし、一部のコードパスでは実際の値が通常より早くに検査され、不一致のときに、奇妙なエラーが発行されたり、エラーにならなかったり、アサート失敗が発生したりする可能性がありました。
(修正前バージョンでは結果が返るが、列数不一致でエラーになるのが正しい) db1=# WITH a(b) AS (VALUES (ROW(1,2,3))) SELECT * FROM a, coalesce(b) AS c(d int, e int); b | d | e ---------+---+--- (1,2,3) | 1 | 2 (1 row)
単一の複合型列を返す SQL言語で実装されたプロシージャでは、アサート失敗またはコアダンプが発生する可能性がありました。
(クラッシュ動作例) db1=# CREATE TYPE typ AS (a INT, b INT); db1=# CREATE PROCEDURE p_udt(OUT typ) LANGUAGE SQL AS $$ SELECT (1, 2); $$; db1=# CALL p_udt(NULL); server closed the connection unexpectedly
関数 date_bin(stride, source, origin) で、source のタイムスタンプが origin のタイムスタンプより前にあり、それらの差がすでに stride の正確な倍数になっている場合、コードは stride を誤って減算していました。誤った問い合わせ結果が発生します。
(誤動作例) db1=# select date_bin('30 minutes'::interval, '2024-01-01 15:00:00'::timestamp, '2024-01-01 17:00:00'::timestamp); date_bin --------------------- 2024-01-01 14:30:00
また、整数オーバーフローも検出するようになりました。いずれも誤った問い合わせ結果の原因となります。
timestamp型の範囲を越えていて「ERROR: timestamp out-of-range」を出すべき一部の場合で、ERROR ではなく誤った問い合わせ結果を返していました。
引数によって参照されるリレーションが同時に削除された場合、関数は NULL を返すべきところですが、エラーになっていました。
2^31 を超える過去のトランザクションID が最近のものとして誤認され、pg_xact_status() または txid_status() の誤動作につながる可能性がありました。
フリースペースマップ(空き領域マップ)は WAL に記録されないため、OS のクラッシュ、レプリカの昇格、PITR リストアなどのエッジケースで、「ERROR: could not read block」が発生する可能性がありました。
WaitEventSetWait は PostgreSQL の内部実装関数です。
実装内部の状態として、待機条件が設定されていない場合に発生します。実際の障害発生例は報告されていませんが、エラー処理で奇妙な動作やクラッシュが生じる可能性が考えられます。
以前は単なるアサーションチェックでしたが、通常の実行時エラーに昇格しました。また、テーブルにアクセスするユーザ定義関数を含む式インデックスを再作成するときに、より的確なエラーメッセージ「ERROR: cannot access index ... while it is being reindexed」が出ます。
(以前のエラー発生例) db1=# CREATE TABLE t34(i int PRIMARY KEY); db1=# CREATE FUNCTION f34(i int) RETURNS int IMMUTABLE LANGUAGE SQL AS $$ SELECT i FROM t34 WHERE i = $1 $$; db1=# CREATE INDEX idx34 ON t34 ( f34(i) ); db1=# INSERT INTO t34 VALUES (1); db1=# REINDEX INDEX idx34; ERROR: could not read block 0 in file "base/26295/26339": read only 0 of 8192 bytes CONTEXT: SQL function "f34" during startup
以前は、インデックスに物理的に格納されている値ではなく、その値へのポインタが呼び出し元に返されていました。これが valgrind でテストしたときに不適切なメモリアクセスとして検出されました。理論的にはクラッシュが発生する可能性がありますが、実際の発生は報告されません。
これにより誤った競合原因を報告する可能性がありました。
サブスクライバがどのテーブルを同期する必要があるかを特定している間に到着した無効化イベントが忘れられていて、新たに同期が必要なテーブルがタイムリーに処理されない可能性がありました。
理論的にはブロッキングモードのソケットで操作することも可能でしたが、長い間完全には機能していませんでした。後で誤動作するよりは接続開始時に失敗した方がよい判断されました。
OpenSSL によって、システムより報告されたエラーを PostgreSQL は、読み取り可能なものではなく、数値のエラーコードで報告していました。
マルチスレッドの libpq クライアントプログラムは、ネットワークルックアップの失敗後に、誤った、あるいは破損したエラーメッセージを受け取る可能性がありました。
GNU gettext の実装では同時呼び出しは問題ないようですが、Windows で利用可能なバージョンではそうではありません。
プログラムがプリプロセッサのコマンド行で定義されたマクロを再定義しようとした場合に発生します。
サーバはパラメータ名の大文字と小文字を区別せずに処理するため、このコードも同様に処理する必要があります。これにより、生成された postgresql.conf ファイルに冗長なエントリが追加されることを回避します。
この問題は「\;」で区切られたクエリ文字列内の、最後のクエリでないクエリのキャンセルの場合にのみ発生していました。
これにより Finder がそのようなファイルを作成するときの問題が回避されます。
この間違いにより、このようなコメントが PL/pgSQL CASE ステートメントの「WHEN」式の後に続く場合、解析エラーが発生していました。
(エラー発生例) db1=# CREATE FUNCTION f50(p1 int) RETURNS text LANGUAGE plpgsql AS $$ BEGIN CASE p1 WHEN 1 -- comment before THEN THEN RETURN 'one'; ELSE RETURN 'other'; END CASE; END; $$; db1=# SELECT f50(1); ERROR: syntax error at end of input LINE 1: SELECT "__Case__Variable_2__" IN (1 -- comment before THEN) ^ QUERY: SELECT "__Case__Variable_2__" IN (1 -- comment before THEN) CONTEXT: PL/pgSQL function f50(integer) line 3 at CASE
ヒープタプルやインデックスタプルの可変長データは、作成時に適用された圧縮パラメータに応じて、短いヘッダか長いヘッダを持つことができます。これらのケースで違いがある場合にエラーを出すのではなく、同等なものとして扱うようになりました。
(エラー例:論理的には同じ 2タプルがあり、ヘッダ長が 1バイトと 4バイトで異なる) db1=# CREATE TABLE t51 (v text); db1=# ALTER TABLE t51 ALTER COLUMN v SET STORAGE PLAIN; db1=# INSERT INTO t51 VALUES ('x'); db1=# COPY t51 TO '/tmp/t51.dat'; db1=# COPY t51 FROM '/tmp/t51.dat'; db1=# CREATE INDEX t51_idx ON t51(v); db1=# CREATE EXTENSION IF NOT EXISTS amcheck; db1=# SELECT bt_index_check('t51_idx', true); ERROR: heap tuple (0,2) from table "t51" lacks matching index tuple within index "t51_idx"
これらの出力関数は、contrib/pageinspect でインデックスエントリを表示するためにのみ使用されるため、誤りが実際に問題になることはほとんどありません。
これは、定数発行サブクエリと「UNION ALL」が関係する場合に発生する可能性がありました。もちろん、定数による並べ替えは無意味ですが、リモートサーバーによって誤って解釈され、「ERROR: ORDER BY position N is not in select list」が発生する危険性もありました。
これは実用上は同じ結果になるはずです。しかし、「GMT」はサーバ内のハードウェアに組み込まれているコードによって認識されますが、「UTC」はタイムゾーンデータベースで検索されます。 そのため、リモートサーバのタイムゾーンデータベースにエントリが欠落しているという万が一の事態が発生した場合、古いコードでは失敗する可能性がありました。
これにより、クラッシュの可能性が回避されました。
(クラッシュ例: 変換対象の t2 が同コマンド内の外側で参照されている) db1=# CREATE TABLE t1 (id int, v text); db1=# CREATE TABLE t2 (id int, v text); db1=# CREATE FUNCTION convert_tbl2view() RETURNS SETOF t1 LANGUAGE plpgsql AS $$ BEGIN EXECUTE 'CREATE RULE "_RETURN" AS ON SELECT TO t2 DO INSTEAD SELECT * FROM t1'; RETURN QUERY EXECUTE 'SELECT * FROM t1 LIMIT 0'; END; $$; db1=# SELECT * FROM t2 UNION ALL SELECT * FROM convert_tbl2view(); server closed the connection unexpectedly