@Don , 쿼리를 실행해 주셔서 감사합니다 - 근본 원인을 확인해 주셨네요
결과가 우리가 의심했던 바로 그 내용을 정확히 보여주고 있습니다.
user_options의 사본이 있는 backup 스키마가 있습니다.
해당 테이블에는 여전히 구버전의 기본값(column_default = false)이 남아 있습니다.
쿼리 결과에서 backup 행이 public보다 앞서 나타났습니다.
마이그레이션이 public.user_options의 기본값을 삭제할 때, backup.user_options에는 영향을 주지 않았습니다. 이후 mark_readonly가 스키마를 필터링하지 않은 채 information_schema.columns를 조회하여, 여전히 기본값이 남아 있는 backup 행을 먼저 가져와 실패했습니다
수정 방법은 쿼리에 table_schema = 'public'을 추가하여 마이그레이션이 실제로 작동하는 스키마만 검사하도록 하는 것입니다.
committed 08:57PM - 10 Jan 26 UTC
## Problem
`Migration::ColumnDropper.mark_readonly` could incorrectly detect a … default value from a non-public schema table.
The query checking for column defaults did not filter by `table_schema`:
```sql
SELECT column_default IS NOT NULL
FROM information_schema.columns
WHERE table_name = :table_name
AND column_name = :column_name
```
When multiple schemas contain tables with the same name (e.g., from backup/restore operations), this query returns multiple rows. The code uses `.first`, making behavior dependent on PostgreSQL's row ordering.
## Root Cause
Don's diagnostic queries on an affected instance confirmed the issue:
```plain
table_schema | column_name | column_default
--------------+---------------------------+----------------
backup | discourse_rewind_disabled | false ← returned first
public | discourse_rewind_disabled | false
```
The `backup` schema (from a previous `pg_dump`) contained a copy of `user_options` with the old default. PostgreSQL returned this row first, causing `mark_readonly` to fail with "You must drop a column's default value before marking it as readonly".
## Fix
Just a oneline -> adding `table_schema = 'public'` to the `WHERE` clause to ensure only the `public` schema is considered.
## Why it couldn't be reproduced locally?
- Fresh dev databases don't have `backup` schemas
- CI environments use clean databases
- Row ordering depends on database history (OIDs, backup/restore cycles)
Ref - https://meta.discourse.org/t/393049