Files
ai_site/platform/internal/dbsync/drop_table.go
whm b04b180d30 feat: harden loose-offline sync for user JWT, schema, and console ops
Enable Binding-scoped agent push/pull, empty-table schema ensure, SyncPage inspect/drop-table, default module import, and agent-bound publish docs from the 宇恒联调意见.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 09:47:35 +08:00

88 lines
2.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}