PostgreSQL 警告をクエリ実行後にクリアして二重表示を防止

rails/rails

PostgreSQL アダプターは、execute メソッドでのみ警告リストをクリアしていたため、select_all など他のクエリで発生した警告が次回のクエリで再度報告される問題がありました。今回の変更は、全てのクエリ実行後に警告を確実に処理・クリアし、同一警告の二重表示を防ぎます。

背景

警告リストがクリアされない ことにより、複数クエリを連続実行した際に前回の警告が残り、execute 以外のメソッドで生成された警告が次のクエリで再度報告されていました。テストコードでも exec_query 後に警告が残るケースが確認されており、実運用での誤解やノイズ増加が懸念されていました。この PR はその状態を修正し、警告の取り扱いを一貫させることを目的としています。

技術的な変更

抽象データベースステートメントの修正

activerecord/lib/active_record/connection_adapters/abstract/database_statements.rbexecute_intent メソッドに ensure ブロックが追加され、クエリ実行後必ず handle_warnings が呼び出されるようになりました。失敗したクエリの場合は、警告処理で発生した例外を元の例外が発生していないときだけ抑制し、元のエラーを隠さない設計です。

@@
-            result = perform_query(conn, intent)
-            intent.raw_result = result
-            handle_warnings(result, intent.processed_sql)
+            begin
+              result = perform_query(conn, intent)
+              intent.raw_result = result
+
+              query_completed = true
+            ensure
+              begin
+                handle_warnings(result, intent.processed_sql)
+              rescue
+                raise if query_completed
+
+                # The query failed, so we need to swallow this exception
+                # from handle_warnings to avoid masking the original.
+              end
+            end

PostgreSQL 固有ステートメントの修正

activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb では、executeensure 部分で警告リストをリセットしていた処理を削除し、代わりに handle_warnings 内で警告配列を取得してから空にしています。これにより、execute だけでなく exec_query など他のメソッドでも同様に警告がクリアされます。

@@
-            @notice_receiver_sql_warnings = []
+            warnings, @notice_receiver_sql_warnings = @notice_receiver_sql_warnings, []
+
+            warnings.each do |warning|
               next if warning_ignored?(warning)

               warning.sql = sql

テストの追加

activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb に 4 つのテストが追加され、警告がクリアされるケース、警告処理が例外を隠さないケース、失敗したクエリ後に次のクエリで警告が正しく取得できるケースを検証しています。これにより、変更の安全性が自動テストで保証されます。

設計判断

警告クリアの責務をクエリ実行層に集約 する方針が採られました。従来は execute のみがリセットを担っていたため、他メソッドでの警告残存という不整合が生じていました。全クエリの完了時に handle_warnings が必ず走るようにしたことで、責務が一元化され、将来別のクエリメソッドが追加されても同様の問題が再発しにくくなります。また、警告処理中の例外は元のクエリが成功した場合にのみ再送出し、失敗時は元の例外を優先することで 例外のマスキング防止 を実現しています。これらの判断はコードの可読性と堅牢性のバランスを考慮した結果です。

まとめ

この PR は、PostgreSQL アダプターが生成する警告を全クエリ実行後に確実に処理・クリアすることで、同一警告の二重表示を防ぎ、例外マスキングを回避する設計変更です。テスト追加により振る舞いが保証され、将来的なクエリ実装拡張でも一貫した警告管理が期待できます。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
e2762159

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)が明確で、背景・技術的変更・設計判断・まとめの各セクションが揃っており、結論がリード文の単なる繰り返しになっていません。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは正しい「言語:ファイルパス」形式ですが、PRリンクが "[PR #57584](URL)" となっており、仕様の "[#123](URL)" 形式と完全に一致していません。リンク形式を修正すればPASSになります。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

対象はRails/ActiveRecord を扱うエンジニアであり、専門用語や実装詳細に焦点が当たっているため適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論→各論→結論の構成を保ち、段落はトピックセンテンスで始まり 1 段落1トピック、長さも適切に分割されています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffと一致しており、変更点が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

handle_warnings、query_completed、warnings などの用語はPRおよびDiffと合致しており誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的主張はDiffとPRの記述に裏付けられており、因果関係も正しく説明されています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

すべての事実はPRタイトル、説明、Diffに基づいており、捏造や推測は見受けられません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号 #57584 が正しく記載されています。その他数値的な記述はありません。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの趣旨「Postgres warnings をクリアする」ことを正確に日本語で表現しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事に外部のバージョンサポート情報やリリース日程等は含まれておらず、PR情報にのみ基づいています。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現の歪曲はなく、PRの記述と一致しています。