fix(store): 修正邻接查询、GC 竞态、备份权限与设置解析,新增 OpenData 纯数据打开

邻接查询 tie-break 与 pinned 排序键与列表序对齐,补表驱动测试(round2 P1-1); GC DELETE 带条件复查,防 SELECT 与 DELETE 间恢复/引用竞态(P2-6); 备份经 umask 收紧创建即 0600,消除 chmod 前暴露窗口(P2-7); page_size 改 strconv.Atoi 全文解析,拒部分解析脏值(P2-13); OpenData 不迁移、不做版本守卫(D6/P1-5)。
This commit is contained in:
2026-09-08 17:32:47 +08:00
parent a885b52f18
commit 132c4a1ba2
5 changed files with 162 additions and 26 deletions
+29 -10
View File
@@ -80,8 +80,32 @@ type Store struct {
db *sql.DB
}
// Open 打开数据库并执行迁移。dbPath 为文件绝对/相对路径。
// Open 打开数据库并执行迁移(start/init 用)。dbPath 为文件绝对/相对路径。
// allowNewer 跳过 user_version 上界守卫(§10.4)。
func Open(dbPath string, allowNewer bool) (*Store, error) {
db, err := openDB(dbPath)
if err != nil {
return nil, err
}
if err := migrateDB(db, allowNewer); err != nil {
db.Close()
return nil, err
}
return &Store{db: db}, nil
}
// OpenData 打开数据库仅做数据操作:**不迁移、不做版本守卫**
// (passwd/backup/gc 维护子命令,D6:在更新 schema 的库上备份/清理
// 不应被守卫阻断,也不应产生迁移副作用)。
func OpenData(dbPath string) (*Store, error) {
db, err := openDB(dbPath)
if err != nil {
return nil, err
}
return &Store{db: db}, nil
}
func openDB(dbPath string) (*sql.DB, error) {
// SQLite URI 不接受相对路径
abs, err := filepath.Abs(dbPath)
if err != nil {
@@ -101,24 +125,19 @@ func Open(dbPath string, allowNewer bool) (*Store, error) {
}
// 单写者串行化(§6.2)
db.SetMaxOpenConns(1)
s := &Store{db: db}
if err := s.migrate(allowNewer); err != nil {
db.Close()
return nil, err
}
return s, nil
return db, nil
}
func (s *Store) migrate(allowNewer bool) error {
func migrateDB(db *sql.DB, allowNewer bool) error {
var v int
if err := s.db.QueryRow("PRAGMA user_version").Scan(&v); err != nil {
if err := db.QueryRow("PRAGMA user_version").Scan(&v); err != nil {
return err
}
if v > MaxSchemaVersion && !allowNewer {
return fmt.Errorf("%w: 库版本 %d > 支持上限 %d", ErrSchemaNewer, v, MaxSchemaVersion)
}
for i := v; i < MaxSchemaVersion; i++ {
tx, err := s.db.Begin()
tx, err := db.Begin()
if err != nil {
return err
}