修复登录500: auth/credentials表缺少tenant_id列
登录时报 Error 1054: Unknown column 'tenant_id' in 'where clause'。 根因:CreateDb里auth/credentials的建表语句从未定义过tenant_id列——这不是 版本跳过导致的迁移遗漏,而是即便全新安装也会触发的建表语句本身的缺陷, 因为查询代码(AuthAddRecord/AuthGetUniqueRecord等)一直在无条件地按 tenant_id过滤/写入这两张表。 同时migration脚本里的dropTenantIDColumns此前会把auth/credentials的 tenant_id也当成"新增多租户特性表的遗留列"一并删掉,跟前面加的列直接打架。 修复: - adapter.go: CreateDb的auth/credentials建表语句补上tenant_id列, 修正未来全新安装的根源问题 - apply_hotgo_tenant_db.go: 补上ALTER TABLE ADD COLUMN(现有数据回填到 默认租户id=1);dropTenantIDColumns排除auth/credentials,不再误删
This commit is contained in:
@@ -566,6 +566,14 @@ func main() {
|
|||||||
"ALTER TABLE tinode.im_youth_mode_settings ADD COLUMN policy_version INT NOT NULL DEFAULT 1 AFTER enabled",
|
"ALTER TABLE tinode.im_youth_mode_settings ADD COLUMN policy_version INT NOT NULL DEFAULT 1 AFTER enabled",
|
||||||
"ALTER TABLE tinode.im_youth_mode_settings ADD COLUMN restrictions JSON AFTER policy_version",
|
"ALTER TABLE tinode.im_youth_mode_settings ADD COLUMN restrictions JSON AFTER policy_version",
|
||||||
"ALTER TABLE tinode.im_youth_mode_settings ADD COLUMN enabled_at DATETIME(3) AFTER restrictions",
|
"ALTER TABLE tinode.im_youth_mode_settings ADD COLUMN enabled_at DATETIME(3) AFTER restrictions",
|
||||||
|
// auth/credentials: server/db/mysql/adapter.go's CreateDb never defined a
|
||||||
|
// tenant_id column here even on a fresh install, yet every auth/credentials
|
||||||
|
// query unconditionally filters/inserts by tenant_id - a latent bug in the
|
||||||
|
// fresh-schema definition, not something version-skip alone explains. Backfill
|
||||||
|
// existing rows to the default tenant (id=1); adapter.go's CREATE TABLE was
|
||||||
|
// fixed alongside this to include the column on future fresh installs too.
|
||||||
|
"ALTER TABLE tinode.auth ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 AFTER id",
|
||||||
|
"ALTER TABLE tinode.credentials ADD COLUMN tenant_id BIGINT NOT NULL DEFAULT 1 AFTER id",
|
||||||
} {
|
} {
|
||||||
if _, err = db.Exec(stmt); err != nil && !strings.Contains(err.Error(), "Duplicate column name") {
|
if _, err = db.Exec(stmt); err != nil && !strings.Contains(err.Error(), "Duplicate column name") {
|
||||||
fatal(fmt.Errorf("exec failed: %s: %w", stmt, err))
|
fatal(fmt.Errorf("exec failed: %s: %w", stmt, err))
|
||||||
@@ -673,10 +681,17 @@ func fatal(v any) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// keptTenantIDTables lists tables whose tenant_id column must survive
|
||||||
|
// dropTenantIDColumns: server/db/mysql/adapter.go queries auth and credentials
|
||||||
|
// by tenant_id unconditionally (not gated behind tenant_db_routing), so unlike
|
||||||
|
// the newer per-tenant-DB feature tables, these two are row-tagged by design.
|
||||||
|
var keptTenantIDTables = "'auth','credentials'"
|
||||||
|
|
||||||
func dropTenantIDColumns(db *sql.DB, schema string) error {
|
func dropTenantIDColumns(db *sql.DB, schema string) error {
|
||||||
fks, err := queryPairs(db, `SELECT DISTINCT table_name, constraint_name
|
fks, err := queryPairs(db, `SELECT DISTINCT table_name, constraint_name
|
||||||
FROM information_schema.KEY_COLUMN_USAGE
|
FROM information_schema.KEY_COLUMN_USAGE
|
||||||
WHERE TABLE_SCHEMA=? AND COLUMN_NAME='tenant_id' AND REFERENCED_TABLE_NAME IS NOT NULL`,
|
WHERE TABLE_SCHEMA=? AND COLUMN_NAME='tenant_id' AND REFERENCED_TABLE_NAME IS NOT NULL
|
||||||
|
AND table_name NOT IN (`+keptTenantIDTables+`)`,
|
||||||
schema)
|
schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -689,7 +704,8 @@ func dropTenantIDColumns(db *sql.DB, schema string) error {
|
|||||||
|
|
||||||
indexes, err := queryPairs(db, `SELECT DISTINCT table_name, index_name
|
indexes, err := queryPairs(db, `SELECT DISTINCT table_name, index_name
|
||||||
FROM information_schema.STATISTICS
|
FROM information_schema.STATISTICS
|
||||||
WHERE TABLE_SCHEMA=? AND COLUMN_NAME='tenant_id' AND INDEX_NAME<>'PRIMARY'`,
|
WHERE TABLE_SCHEMA=? AND COLUMN_NAME='tenant_id' AND INDEX_NAME<>'PRIMARY'
|
||||||
|
AND table_name NOT IN (`+keptTenantIDTables+`)`,
|
||||||
schema)
|
schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -702,6 +718,7 @@ func dropTenantIDColumns(db *sql.DB, schema string) error {
|
|||||||
|
|
||||||
rows, err := db.Query(`SELECT table_name FROM information_schema.COLUMNS
|
rows, err := db.Query(`SELECT table_name FROM information_schema.COLUMNS
|
||||||
WHERE TABLE_SCHEMA=? AND COLUMN_NAME='tenant_id'
|
WHERE TABLE_SCHEMA=? AND COLUMN_NAME='tenant_id'
|
||||||
|
AND table_name NOT IN (`+keptTenantIDTables+`)
|
||||||
ORDER BY table_name`, schema)
|
ORDER BY table_name`, schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -657,7 +657,8 @@ func (a *adapter) CreateDb(reset bool) error {
|
|||||||
// Authentication records for the basic authentication scheme.
|
// Authentication records for the basic authentication scheme.
|
||||||
if _, err = tx.Exec(
|
if _, err = tx.Exec(
|
||||||
`CREATE TABLE auth(
|
`CREATE TABLE auth(
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
tenant_id BIGINT NOT NULL,
|
||||||
uname VARCHAR(32) NOT NULL,
|
uname VARCHAR(32) NOT NULL,
|
||||||
userid BIGINT NOT NULL,
|
userid BIGINT NOT NULL,
|
||||||
scheme VARCHAR(16) NOT NULL,
|
scheme VARCHAR(16) NOT NULL,
|
||||||
@@ -835,6 +836,7 @@ func (a *adapter) CreateDb(reset bool) error {
|
|||||||
if _, err = tx.Exec(
|
if _, err = tx.Exec(
|
||||||
`CREATE TABLE credentials(
|
`CREATE TABLE credentials(
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id INT NOT NULL AUTO_INCREMENT,
|
||||||
|
tenant_id BIGINT NOT NULL,
|
||||||
createdat DATETIME(3) NOT NULL,
|
createdat DATETIME(3) NOT NULL,
|
||||||
updatedat DATETIME(3) NOT NULL,
|
updatedat DATETIME(3) NOT NULL,
|
||||||
deletedat DATETIME(3),
|
deletedat DATETIME(3),
|
||||||
|
|||||||
Reference in New Issue
Block a user