[v14.0/forgejo] fix: recreate-tables doesn't work on PostgreSQL with multiple Forgejo schemas (#10870)

**Backport:** https://codeberg.org/forgejo/forgejo/pulls/10854

Discovered while trying to reproduce #10848 -- when using `forgejo doctor recreate-tables` against a PostgreSQL database with multiple Forgejo schemas in it, it fails.  The reason is that when querying for index and sequence information, it begins to get information from the other schemas.

```
2026/01/15 15:19:15 ...3.6.1/command_run.go:288:run() [I] PING DATABASE postgresschema
2026/01/15 15:19:15 ...igrations/base/db.go:51:func2() [I] Creating temp table: tmp_recreate__external_login_user for Bean: ExternalLoginUser
2026/01/15 15:19:15 ...igrations/base/db.go:108:func2() [I] Copying table external_login_user to temp table tmp_recreate__external_login_user
2026/01/15 15:19:15 ...igrations/base/db.go:120:func2() [I] Dropping existing table external_login_user, and renaming temp table tmp_recreate__external_login_user in its place
2026/01/15 15:19:15 cmd/doctor.go:216:func1() [E] [Error SQL Query] ALTER INDEX "external_login_user_pkey" RENAME TO "external_login_user_pkey" [] - ERROR: relation "external_login_user_pkey" does not exist (SQLSTATE 42P01)
2026/01/15 15:19:15 ...igrations/base/db.go:404:renameTable() [E] Unable to rename external_login_user_pkey to external_login_user_pkey. Error: ERROR: relation "external_login_user_pkey" does not exist (SQLSTATE 42P01)
Command error: migrate: ERROR: relation "external_login_user_pkey" does not exist (SQLSTATE 42P01)
```

This is a very niche use-case that is likely to only affect a developer using PostgreSQL and popping back to older releases often enough to keep them around in different DB schemas.  I don't think it's worth an automated test, which would require creating a secondary DB schema in a specific migration test.  Manually tested on my dev environment.

Co-authored-by: Mathieu Fenniak <mathieu@fenniak.net>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10870
Reviewed-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
Co-committed-by: forgejo-backport-action <forgejo-backport-action@noreply.codeberg.org>
This commit is contained in:
forgejo-backport-action 2026-01-16 11:41:57 +01:00 committed by Michael Kriese
commit e147d8d805

View file

@ -363,7 +363,7 @@ func renameTable(sess *xorm.Session, bean any, tableName, tempTableName string,
schema := sess.Engine().Dialect().URI().Schema
sess.Engine().SetSchema("")
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE ? || '_id_seq' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&originalSequences); err != nil {
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_schema = ? AND (sequence_name LIKE ? || '_id_seq' AND sequence_catalog = ?)", schema, tableName, setting.Database.Name).Find(&originalSequences); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
@ -392,7 +392,7 @@ func renameTable(sess *xorm.Session, bean any, tableName, tempTableName string,
var indices []string
sess.Engine().SetSchema("")
if err := sess.Table("pg_indexes").Cols("indexname").Where("tablename = ? ", tableName).Find(&indices); err != nil {
if err := sess.Table("pg_indexes").Cols("indexname").Where("tablename = ? AND schemaname = ?", tableName, schema).Find(&indices); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}
@ -408,7 +408,7 @@ func renameTable(sess *xorm.Session, bean any, tableName, tempTableName string,
var sequences []string
sess.Engine().SetSchema("")
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_name LIKE 'tmp_recreate__' || ? || '_id_seq' AND sequence_catalog = ?", tableName, setting.Database.Name).Find(&sequences); err != nil {
if err := sess.Table("information_schema.sequences").Cols("sequence_name").Where("sequence_schema = ? AND sequence_name LIKE 'tmp_recreate__' || ? || '_id_seq' AND sequence_catalog = ?", schema, tableName, setting.Database.Name).Find(&sequences); err != nil {
log.Error("Unable to rename %s to %s. Error: %v", tempTableName, tableName, err)
return err
}