PostgreSQLのスキーマ修飾テーブルに対するインデックスコメントのバグ修正

rails/rails

スキーマ修飾テーブル(例: "other_schema.widgets")に comment: オプション付きで add_index を呼び出すと、COMMENT ON INDEX 文のインデックス名がスキーマ修飾されず PG::UndefinedTable エラーが発生する問題が修正されました。

背景

PostgreSQLでは、インデックスコメントのSQL文においてインデックス名をスキーマ修飾名で参照する必要があります。other_schema 上に作成されたインデックスは "other_schema"."index_widgets_on_id" と指定しなければならず、"index_widgets_on_id" だけでは対象のリレーションが見つかりません。

#56581 で報告されたとおり、以下の手順で問題を再現できます。

ActiveRecord::Base.connection.execute("CREATE SCHEMA other_schema")
ActiveRecord::Base.connection.create_table("other_schema.widgets")
ActiveRecord::Base.connection.add_index(
  "other_schema.widgets",
  :id,
  comment: "test comment"
)

Active Record はインデックス自体は正しく other_schema 上に作成するものの、続く COMMENT ON INDEX 文では非修飾名を使用していたため、以下のエラーが発生していました。

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: relation "index_widgets_on_id" does not exist

この不一致は、change_index_comment_sql がインデックス名だけを受け取り、テーブル名(=スキーマ情報)を持たない設計に起因していました。

技術的な変更

change_index_comment_sql メソッドのシグネチャに table_name 引数が追加され、PostgreSQL実装側でスキーマ修飾名を生成するロジックが加わりました。

抽象基底クラス schema_statements.rb の2か所で table_name を渡すよう変更されています。1つは create_table 内でインデックスコメントを発行する箇所、もう1つは add_index 後にコメントを発行する箇所です。

変更前:

statements << change_index_comment_sql(index_definition.index) if index_definition.index.comment.present?
# ...
def change_index_comment_sql(index)
  raise NotImplementedError
end

変更後:

statements << change_index_comment_sql(index_definition.index, table_name) if index_definition.index.comment.present?
# ...
def change_index_comment_sql(index, table_name)
  raise NotImplementedError
end

PostgreSQL固有の実装では、Utils.extract_schema_qualified_name でテーブル名からスキーマ部分を抽出し、スキーマが存在する場合は PostgreSQL::Name.new(name.schema, index.name) でスキーマ修飾インデックス名を組み立てます。

変更前:

def change_index_comment_sql(index)
  "COMMENT ON INDEX #{quote_column_name(index.name)} IS #{quote(index.comment)}"
end

変更後:

def change_index_comment_sql(index, table_name)
  name = Utils.extract_schema_qualified_name(table_name.to_s)
  index_name = name.schema ? PostgreSQL::Name.new(name.schema, index.name).to_s : index.name

  "COMMENT ON INDEX #{quote_table_name(index_name)} IS #{quote(index.comment)}"
end

name.schemanil の場合(スキーマ修飾なしのテーブル名)は従来どおり非修飾の index.name を使うため、既存の動作との後方互換性は維持されます。また、引用処理が quote_column_name から quote_table_name に変更されており、"schema"."index_name" のようなドット区切り名を正しくクォートできます。

テストとして test_index_with_comment_on_table_with_schema が追加され、second_schema.posts 上のインデックスにコメントが正しく設定されることを検証しています。

設計判断

スキーマ情報の取得に既存の Utils.extract_schema_qualified_name ユーティリティが再利用されています。add_indexcreate_table でテーブル名のスキーマ解析に使われているのと同じ仕組みであり、新たなパース処理を追加せずに一貫性を保てます。

change_index_comment_sql を抽象メソッドとして table_name を受け取る設計に変更したことで、PostgreSQL以外のアダプターが同メソッドをオーバーライドする際も同じインターフェースに従うことになります。これにより、将来的に他のアダプターがスキーマ修飾の考慮を必要とする場合にも対応しやすくなっています。

まとめ

本PRは、change_index_comment_sql にテーブル名を渡すという最小限の変更で、インデックス作成とコメント付与のSQL文に一貫したスキーマ修飾名が使われるよう修正しています。スキーマ修飾テーブルを利用するPostgreSQLアプリケーションでは、add_indexcomment: オプションが期待どおり動作するようになります。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
c2830d4d

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)、背景・技術的な変更・設計判断(各論)、まとめ(結論)の3部構成が明確に守られています。各セクションの役割が明確で、非常に理解しやすい構成です。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:path/to/file.rb)およびGitHubのIssue/PRへのリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

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

Active Recordの内部実装やPostgreSQLのスキーマに関する内容であり、専門知識を持つエンジニアという対象読者に適合しています。不要な初心者向けの解説はありません。

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

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

各セクションが総論→各論の構成になっており、各段落はトピックセンテンスで始まり、1段落1トピックの原則が守られています。段落の長さも適切で、可読性が高いです。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコードは、提供されたDiff情報と正確に一致しています。変更前後のコードが的確に示されており、変更の意図を正しく伝えています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「スキーマ修飾テーブル」「PG::UndefinedTable」「quote_table_name」など、PRや関連技術で用いられる用語が正確かつ適切に使用されています。

説明の技術的正確性 ✓ PASS

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

インデックスコメントのSQL生成時にスキーマ修飾名が使われずエラーが発生するという問題の原因と、`table_name`を渡すことで解決するという修正内容の説明は、技術的に正確かつ論理的です。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのDescription、Title、Diffの内容によって裏付けられています。特に「設計判断」セクションは、コードから読み取れる妥当な分析であり、ハルシネーションは見られません。

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

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

PR番号(#56582)と関連Issue番号(#56581)が正確に記載され、正しくリンクされています。

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

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

記事のタイトル「PostgreSQLのスキーマ修飾テーブルに対するインデックスコメントのバグ修正」は、PRのタイトルと内容を正確に反映しています。

外部知識の正確性 ✓ PASS

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

記事はPRで提供された情報に完全に基づいており、バージョンのサポート状況やリリース予定など、PR外の知識の捏造はありません。

時間表現の正確性 ✓ PASS

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

記事には時間表現の歪曲は見られず、PRで示された事実関係を正確に記述しています。