updater.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package core
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  4. "git.ycl.pub/yl32940/TsDB2/DB/core/util"
  5. "encoding/binary"
  6. )
  7. // Updater 更新操作对象
  8. type Updater struct {
  9. table *Table
  10. updates map[string]interface{}
  11. where Condition
  12. }
  13. // Update 返回更新操作对象
  14. func (table *Table) Update() *Updater {
  15. return &Updater{
  16. table: table,
  17. updates: make(map[string]interface{}),
  18. }
  19. }
  20. // Set 设置更新字段
  21. func (u *Updater) Set(field string, value interface{}) *Updater {
  22. u.updates[field] = value
  23. return u
  24. }
  25. // Where 设置更新条件
  26. func (u *Updater) Where(cond Condition) *Updater {
  27. u.where = cond
  28. return u
  29. }
  30. // Exec 执行更新
  31. func (u *Updater) Exec() (int64, error) {
  32. // 找承载行数据的一级索引名 (由处理器自报, 本层不认识索引类型)
  33. pkIdxName := ""
  34. if pkMeta, _, ok := u.table.indexMeta.rowStoreMeta(); ok {
  35. pkIdxName = util.BytesToString(pkMeta.IndexName[:])
  36. }
  37. if pkIdxName == "" {
  38. return 0, nil
  39. }
  40. // 先收集匹配行的真实 pkID, 再逐行改。
  41. // 两处都不能沿用旧实现:
  42. // - 用 Find() 收集会把每一行都反序列化成 []FieldValue, 万行级的更新白占内存,
  43. // 这里只物化 pkID;
  44. // - pkID 必须取行前缀里的真实值。行数据里没有 pkID 字段, 旧实现只能"取第一个
  45. // uint64 字段值当 pkID", 主键列不是行内第一个 8 字节列时会改到另一行上。
  46. var pkIDs []uint64
  47. if err := u.table.Query().Where(u.where).scanWithPKID(func(pkID uint64, _ []types.FieldValue) bool {
  48. pkIDs = append(pkIDs, pkID)
  49. return true
  50. }); err != nil {
  51. return 0, err
  52. }
  53. var count int64
  54. for _, pkID := range pkIDs {
  55. key := make([]byte, 8)
  56. binary.BigEndian.PutUint64(key, pkID)
  57. // 只把本次要改的字段交给 UpdateRow, 其余列由 serializeRow 沿用旧值
  58. var values []types.FieldValue
  59. for field, val := range u.updates {
  60. values = append(values, types.FieldValue{
  61. FieldName: []byte(field),
  62. Value: val,
  63. })
  64. }
  65. // 过去这里写成 `if err == nil { count++ }`, 把失败行悄悄跳过:
  66. // 调用方会拿到成功的行数, 却不知道有行没更新。必须向上抛出。
  67. if err := u.table.UpdateRow(pkIdxName, key, values); err != nil {
  68. return count, err
  69. }
  70. count++
  71. }
  72. return count, nil
  73. }