package dbsync import ( "context" "fmt" "strings" ) // DropTableResult 控制台删表结果。 type DropTableResult struct { OK bool `json:"ok"` Side string `json:"side"` Table string `json:"table"` Dropped bool `json:"dropped"` MetaCleared int64 `json:"meta_cleared,omitempty"` Message string `json:"message,omitempty"` } // DropTableOnEndpoint 删除业务表(禁止 _ajz_*);并清理 _ajz_sync_meta 中该表残留。 // 注意:仅作用于当前 endpoint(线上 A 或本机 B),不向另一侧同步 DDL。 func DropTableOnEndpoint(ctx context.Context, ep Endpoint, side, table string) (*DropTableResult, error) { table = strings.TrimSpace(table) side = strings.TrimSpace(side) if side == "" { side = "remote" } if table == "" { return nil, fmt.Errorf("table required") } if strings.HasPrefix(table, "_ajz_") { return nil, fmt.Errorf("同步系统表不可删: %s", table) } if strings.EqualFold(table, "sqlite_master") || strings.HasPrefix(strings.ToLower(table), "sqlite_") { return nil, fmt.Errorf("系统表不可删: %s", table) } db, owned, err := openInspectDB(ep) if err != nil { return &DropTableResult{OK: false, Side: side, Table: table, Message: err.Error()}, err } if owned { defer db.Close() } exists, err := tableExists(ctx, db, ep.Driver, table) if err != nil { return nil, err } if !exists { return &DropTableResult{ OK: true, Side: side, Table: table, Dropped: false, Message: "表不存在(可能已删)", }, nil } ddl := fmt.Sprintf(`DROP TABLE IF EXISTS %s`, quoteIdent(ep.Driver, table)) if _, err := db.ExecContext(ctx, ddl); err != nil { return nil, fmt.Errorf("drop table: %w", err) } var metaCleared int64 if metaExists, _ := tableExists(ctx, db, ep.Driver, MetaTable); metaExists { q := fmt.Sprintf(`DELETE FROM %s WHERE table_name = ?`, quoteIdent(ep.Driver, MetaTable)) if ep.Driver == DriverPostgres { q = fmt.Sprintf(`DELETE FROM %s WHERE table_name = $1`, quoteIdent(ep.Driver, MetaTable)) } res, err := db.ExecContext(ctx, q, table) if err == nil && res != nil { metaCleared, _ = res.RowsAffected() } } // 若该 DSN 在 remote 池里,丢掉缓存连接,避免旧 schema 缓存感。 InvalidateRemote(ep.Driver, ep.DSN) return &DropTableResult{ OK: true, Side: side, Table: table, Dropped: true, MetaCleared: metaCleared, Message: "已删除;若另一侧仍有同名表,不会自动同步删除,需分别处理或避免再次 push/ensure", }, nil }