convert.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. package DB
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  4. "bytes"
  5. "encoding/binary"
  6. "fmt"
  7. "io"
  8. "math/big"
  9. "reflect"
  10. "strings"
  11. )
  12. // structToFieldValues 将结构体转换为 core.InsertRow 所需的 FieldValue 切片
  13. //
  14. // activeColumns 为当前 DB schema 活跃列集合, 只发送交集内的字段。
  15. //
  16. // blobc: Blob 列的写入入口 (一般是 *core.Transaction, 包成 types.BlobCommitter 接口)。
  17. // 传 nil 时 Blob 列必须已经"自带" types.BlobRef (写侧用户在 tx 外自行 blob.Commit 然后送 ref),
  18. // 否则 blob 列会报错 — 这是把"必须有 tx 才能写 blob"的要求显式化, 防止新写代码在无 tx
  19. // 上下文里静默走错路径。
  20. func structToFieldValues(obj interface{}, model *ModelInfo, activeColumns map[string]bool, blobc types.BlobCommitter) ([]types.FieldValue, error) {
  21. v := reflect.ValueOf(obj)
  22. if v.Kind() == reflect.Ptr {
  23. v = v.Elem()
  24. }
  25. if v.Kind() != reflect.Struct {
  26. return nil, fmt.Errorf("vrtx: expected struct, got %s", v.Kind())
  27. }
  28. result := make([]types.FieldValue, 0, len(model.AllFields))
  29. for _, fd := range model.AllFields {
  30. // 跳过不在当前 DB schema 中的字段 (如已删除列、或 struct 有但 DB 没有)
  31. if activeColumns != nil && !activeColumns[fd.ColName] {
  32. continue
  33. }
  34. // 快路径: 建模时解析好的反射路径直接取 (含嵌入提升链);
  35. // 指针嵌入等特殊路径解析不到时退回 findField 老逻辑
  36. fv := fieldByModelPath(v, fd, model.StructType)
  37. if !fv.IsValid() {
  38. // 字段不在结构体中 (如自动添加的 _id),用零值填充
  39. result = append(result, types.FieldValue{
  40. FieldName: fd.ColNameBytes,
  41. Value: zeroValue(fd),
  42. })
  43. continue
  44. }
  45. // 指针/接口字段为 nil, 且该列声明了 nullable → 显式 NULL。
  46. // 不做这一步的话, 接口里装的是"类型化 nil" (*T)(nil): core 侧的 `value == nil`
  47. // 判不出来, 会被当成零值写进去 —— "可空列永远存不出 NULL", 唯一约束的 NULL
  48. // 免除也就无从生效。只认指针/接口: nil 切片是"空值"而不是 NULL (空 blob 的
  49. // 既有语义必须保持), 非可空列则继续走"nil 当零值"的老路。
  50. if fd.Flag&types.FlagNullable != 0 && isNilPointerValue(fv) {
  51. result = append(result, types.FieldValue{
  52. FieldName: fd.ColNameBytes,
  53. Value: nil,
  54. })
  55. continue
  56. }
  57. val, err := normalizeValue(fv, fd, blobc)
  58. if err != nil {
  59. return nil, err
  60. }
  61. result = append(result, types.FieldValue{
  62. FieldName: fd.ColNameBytes,
  63. Value: val,
  64. })
  65. }
  66. return result, nil
  67. }
  68. // fieldValuesToStruct 将 core 查询结果的 FieldValue 切片反序列化到结构体
  69. //
  70. // blobReader: Blob 列的读取入口 (一般是 *core.Table)。行内只有 8B BlobRef, 载体又是
  71. // []byte (见 types.go 对 Blob 列载体的约束), 所以必须在这里按 ref 把链页内容读回内存。
  72. // 该列为空 (全是非 blob 列 / 值是空 ref) 时可以不传, 传 nil 只在真遇到非空 blob 时才会报错。
  73. func fieldValuesToStruct(fvs []types.FieldValue, model *ModelInfo, obj interface{}, blobReader types.BlobReader) error {
  74. v := reflect.ValueOf(obj)
  75. if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
  76. return fmt.Errorf("vrtx: obj must be a pointer to struct")
  77. }
  78. v = v.Elem()
  79. // 逐列直查预建的 列名→AllFields下标 映射: map 查找里的 string([]byte) 是编译器
  80. // 优化不分配, 省掉旧实现"每行建一张 colMap + 每列一次 string 分配 + 2N 次哈希"。
  81. // 交付列里模型没有的直接跳过; 模型里有但本行没交付的字段保持零值 —— 与旧实现一致。
  82. for i := range fvs {
  83. fv := &fvs[i]
  84. fi, ok := model.ColIndex[string(fv.FieldName)]
  85. if !ok {
  86. continue
  87. }
  88. fd := &model.AllFields[fi]
  89. target := fieldByModelPath(v, *fd, model.StructType)
  90. if !target.IsValid() || !target.CanSet() {
  91. continue
  92. }
  93. if err := setFieldFromValue(target, fv.Value, *fd, blobReader); err != nil {
  94. return fmt.Errorf("vrtx: set field %s: %w", fd.Name, err)
  95. }
  96. }
  97. return nil
  98. }
  99. // fieldByModelPath 建模时解析好的反射路径直接取字段 (含嵌入提升链)。
  100. //
  101. // 逐行路径 (structToFieldValues / getPKValue / setPKValue / fieldValuesToStruct)
  102. // 每行每列一次字段查找, FieldByName 的类型级搜索会为闭包与 Index 切片反复分配
  103. // (批量灌数实测 ~18% 的分配量); GoPath 是 ParseModel 时一次性算好的, 取值只是
  104. // O(路径长度) 的指针解引用。解析不到 (字段不在结构体里 / 路径无效) 时退回
  105. // findField 老逻辑, 语义不变。
  106. func fieldByModelPath(v reflect.Value, fd FieldDef, t reflect.Type) reflect.Value {
  107. if fd.GoPath != nil {
  108. if f, err := v.FieldByIndexErr(fd.GoPath); err == nil {
  109. return f
  110. }
  111. }
  112. return findField(v, fd.Name, t)
  113. }
  114. // findField 在结构体中查找字段 (支持嵌入结构体)
  115. func findField(v reflect.Value, name string, t reflect.Type) reflect.Value {
  116. // 直接查找
  117. if f := v.FieldByName(name); f.IsValid() {
  118. return f
  119. }
  120. // 在嵌入结构体中查找
  121. for i := 0; i < t.NumField(); i++ {
  122. sf := t.Field(i)
  123. if sf.Anonymous {
  124. fv := v.Field(i)
  125. if sf.Type == baseModelType || sf.Type == timeSeriesModelType {
  126. if inner := fv.FieldByName(name); inner.IsValid() {
  127. return inner
  128. }
  129. } else if sf.Type.Kind() == reflect.Struct {
  130. if inner := findField(fv, name, sf.Type); inner.IsValid() {
  131. return inner
  132. }
  133. }
  134. }
  135. }
  136. return reflect.Value{}
  137. }
  138. // backfillBlobRefs Insert/Update 成功后把落库拿到的 BlobRef 回填进对象。
  139. //
  140. // 只处理流式载体 types.Blob 的字段: 序列化时字段值被换成行内 8B ref, 但对象里的
  141. // Source/Bytes 原样留着 —— 两个后果都实际伤人:
  142. //
  143. // 1. Insert 后对象不知道自己的链在哪 (row.Data.FirstPageID == 0), demo/上层无从
  144. // 引用;
  145. // 2. 更致命: structToFieldValues 无脏字段跟踪, 后续 Update 会全列重序列化。
  146. // 零值 types.Blob 走 blobFieldToRef 得到空 ref —— 用户只是改了 Name 调一次
  147. // Update, blob 链就被整体抹成空。
  148. //
  149. // 回填即根治: 清掉已消费的 Source/Bytes, 填入 FirstPageID/TotalLen —— 下次 Update
  150. // 走 blobFieldToRef 的"读回镜像"分支 (FirstPageID != 0 且无内容), 原 ref 原样下传,
  151. // 链不动。[]byte 载体不需要回填 (它就是内容本身, 每次全量重写是既定语义)。
  152. func backfillBlobRefs(obj interface{}, model *ModelInfo, fvs []types.FieldValue) {
  153. v := reflect.ValueOf(obj)
  154. if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
  155. return
  156. }
  157. v = v.Elem()
  158. blobType := reflect.TypeOf(types.Blob{})
  159. for _, fd := range model.AllFields {
  160. if fd.FieldType != types.FieldType_Blob {
  161. continue
  162. }
  163. target := fieldByModelPath(v, fd, model.StructType)
  164. if !target.IsValid() || !target.CanSet() || target.Type() != blobType {
  165. continue
  166. }
  167. for _, fv := range fvs {
  168. if string(fv.FieldName) != fd.ColName {
  169. continue
  170. }
  171. ref, ok := fv.Value.(types.BlobRef)
  172. if !ok {
  173. continue
  174. }
  175. // Source/Bytes 清掉: 流已被 BlobCommit 消费 (reader 位于 EOF),
  176. // 留着只会让下一次 Update 把死流再灌一遍或报错。
  177. target.Set(reflect.ValueOf(types.Blob{
  178. FirstPageID: ref.FirstPageID,
  179. TotalLen: ref.TotalLen,
  180. }))
  181. }
  182. }
  183. }
  184. // normalizeValue 将反射字段值转换为 core 可接受的值
  185. //
  186. // blobc: Blob 列的写入入口 (一般是 *core.Transaction). 传 nil 时要求字段已经自带
  187. // types.BlobRef — 否则 blob 列会报错, 这是把"必须有 tx 才能写 blob"的要求显式化。
  188. func normalizeValue(fv reflect.Value, fd FieldDef, blobc types.BlobCommitter) (interface{}, error) {
  189. iface := fv.Interface()
  190. // 指针载体解一层: 可空列用 `*T` 表达 (nil 已在上层被转成显式 NULL, 走不到这里),
  191. // 非 nil 的指针要按 T 的值走下面的转换。不解这一层的话, *int64 会被 toUint64 的
  192. // "既不能 CanUint 也不能 CanInt" 分支静默变成 0 —— 可空列看着能写, 写进去全是零。
  193. //
  194. // 只给下面这些"由 normalizeValue 定值"的列型解引用; 扩展类型那组是"原样下传",
  195. // 其中 Int128 的载体本来就是 *big.Int (core 按指针识别), 绝不能解开。
  196. carrier := iface
  197. if fv.Kind() == reflect.Ptr && !fv.IsNil() {
  198. carrier = fv.Elem().Interface()
  199. }
  200. switch fd.FieldType {
  201. case types.FieldType_Uint8:
  202. return uint8(toUint64(carrier)), nil
  203. case types.FieldType_Uint16:
  204. return toInt16(carrier), nil
  205. case types.FieldType_Uint32:
  206. return toInt32(carrier), nil
  207. case types.FieldType_Uint64:
  208. return toUint64(carrier), nil
  209. case types.FieldType_Int8:
  210. return toInt8(carrier), nil
  211. case types.FieldType_Int16:
  212. return toInt16(carrier), nil
  213. case types.FieldType_Int32:
  214. return toInt32(carrier), nil
  215. case types.FieldType_Int64:
  216. return toInt64(carrier), nil
  217. case types.FieldType_Float64:
  218. return toFloatVal(carrier), nil
  219. case types.FieldType_String:
  220. // 字符串 / []byte 载体【原样下传】: 补零与"超宽报错"都由 types.EncodeValue
  221. // 按列的实际宽度完成 —— 宽度只有一个权威来源 (见 FieldDef.Width)。
  222. //
  223. // 旧实现先在这里 toFixedBytes 一次, 而那个函数是 copy 进定长缓冲: 超宽部分被
  224. // 静默丢掉。`maxlen:10` 的列写 20 字节会成功落库并少掉一半内容, 调用方拿不到
  225. // 任何信号 —— 这正是列宽闸门要拦的事, 拦在 ORM 就会绕过它。
  226. switch carrier.(type) {
  227. case string, []byte:
  228. return carrier, nil
  229. }
  230. // 数值载体 (String 兼作裸字节列的旧用法) 仍按列宽做 BigEndian 编码
  231. return toFixedBytes(carrier, int(fd.Width())), nil
  232. case types.FieldType_Dynamicbyte:
  233. // 动态列必须送 []byte: 引擎侧对动态列只做 `value.([]byte)` 断言,
  234. // 送 string / 数值会在那里被明确拒绝 (见 core.writeFieldValueAt)。
  235. return toBytes(carrier), nil
  236. case types.FieldType_Blob:
  237. // 字段值可以是:
  238. // - types.Blob{Source, Bytes} 写侧
  239. // - types.BlobRef{TotalLen, FirstPageID} 已 commit 的 ref
  240. // - []byte / string / io.Reader / *os.File (裸承载, 引擎帮包 Blob)
  241. // - nil 空 blob (NULL 已经被走掉了)
  242. // 全部统一为 types.BlobRef 后才下传; 非空 blob 必须有 blobc, 否则报"无 tx"。
  243. return blobFieldToRef(carrier, fd, blobc)
  244. // ===== 扩展类型 =====
  245. //
  246. // 这几类一律"原样下传", 由 core 的 types.EncodeValue 做规范化与校验 ——
  247. // 它才是唯一知道列级参数 (Decimal 的 scale) 的地方。这里若先做一次宽松转换,
  248. // 反而会把"不能精确表示"的值悄悄变成另一个值 (例如 float64→float32 截断)。
  249. case types.FieldType_Bool:
  250. return iface, nil
  251. case types.FieldType_Float32:
  252. return iface, nil
  253. case types.FieldType_Decimal:
  254. return iface, nil
  255. case types.FieldType_UUID:
  256. return iface, nil
  257. case types.FieldType_Year:
  258. return iface, nil
  259. case types.FieldType_Int128:
  260. return iface, nil
  261. default:
  262. return iface, nil
  263. }
  264. }
  265. // blobFieldToRef 把 ORM 字段值 (任意受支持的载体) 转成 types.BlobRef。
  266. //
  267. // 受支持的载体:
  268. // - nil → (BlobRef{}, nil) 空 blob
  269. // - types.BlobRef{} → 原值返回 已 commit 的 ref
  270. // - types.Blob{} → 通过 blobc.BlobCommit 写入链页, 拿 ref
  271. // - []byte → 包成 types.Blob{Bytes} 再 BlobCommit
  272. // - string → []byte 后同上
  273. // - io.Reader → 包成 types.Blob{Source} 再 BlobCommit; 文件、网络等
  274. //
  275. // 任一种都不该要求用户传 tx — ORM 层已自动开 tx, 把 tx.BlobCommit 包成 blobc 即可。
  276. //
  277. // 错误处理: Source 与 Bytes 同时非 nil 报"二选一"; blobc == nil 而字段非空 ref 报
  278. // "无 tx"; io.Reader 读取失败等按 tx.BlobCommit 的既有错误处理。
  279. func blobFieldToRef(carrier interface{}, fd FieldDef, blobc types.BlobCommitter) (types.BlobRef, error) {
  280. if carrier == nil {
  281. return types.BlobRef{}, nil
  282. }
  283. switch v := carrier.(type) {
  284. case types.BlobRef:
  285. return v, nil
  286. case types.Blob:
  287. // Blob 里"已读回"模式 (FirstPageID/TotalLen/Compress 已填) 直接转 ref;
  288. // 写侧 (Source/Bytes) 需要 blobc.
  289. //
  290. // 判定顺序很关键: 必须先看 FirstPageID 再判空。types.Blob.Empty() 的写侧判空
  291. // 是 "Source 与 Bytes 都空", 但"读回镜像"(引擎 Find 填的 ref / backfillBlobRefs
  292. // 回填的 ref) 恰恰就是 Source/Bytes 全空、FirstPageID 非 0 —— 若先按
  293. // "Source==nil && Bytes==空 => 空 blob" 短路, 镜像会被误判成空, Update 一发
  294. // 整条链就被抹掉 (曾经正是这么写的, 镜像分支成了死代码)。
  295. if v.FirstPageID != 0 && v.Source == nil && len(v.Bytes) == 0 {
  296. return types.BlobRef{TotalLen: v.TotalLen, FirstPageID: v.FirstPageID}, nil
  297. }
  298. if v.Source == nil && len(v.Bytes) == 0 {
  299. return types.BlobRef{}, nil
  300. }
  301. if blobc == nil {
  302. return types.BlobRef{}, fmt.Errorf("vrtx: blob 列 %s 需要事务上下文才能写, 请在 ORM 操作内自动 begin-tx (或显式 tx.BeginTransaction)", fd.ColName)
  303. }
  304. return blobc.BlobCommit(blobCarrier(v), types.CompressNone)
  305. case []byte:
  306. if len(v) == 0 {
  307. return types.BlobRef{}, nil
  308. }
  309. if blobc == nil {
  310. return types.BlobRef{}, fmt.Errorf("vrtx: blob 列 %s 需要事务上下文才能写", fd.ColName)
  311. }
  312. return blobc.BlobCommit(bytes.NewReader(v), blobCompressOf(v))
  313. case string:
  314. if len(v) == 0 {
  315. return types.BlobRef{}, nil
  316. }
  317. if blobc == nil {
  318. return types.BlobRef{}, fmt.Errorf("vrtx: blob 列 %s 需要事务上下文才能写", fd.ColName)
  319. }
  320. return blobc.BlobCommit(strings.NewReader(v), blobCompressOfString(v))
  321. }
  322. // 兜底: 任何 io.Reader 实现都直接接受 (*os.File, *bytes.Reader, *bytes.Buffer, ...).
  323. if r, ok := carrier.(io.Reader); ok {
  324. if blobc == nil {
  325. return types.BlobRef{}, fmt.Errorf("vrtx: blob 列 %s 需要事务上下文才能写", fd.ColName)
  326. }
  327. return blobc.BlobCommit(r, types.CompressNone)
  328. }
  329. return types.BlobRef{}, fmt.Errorf("vrtx: blob 列 %s 不支持的载体类型 %T", fd.ColName, carrier)
  330. }
  331. // blobCarrier 把 types.Blob 折成单个 io.Reader (BlobCommit 只接一个 reader)。
  332. //
  333. // 优先级: Source > Bytes. 同时给时会"明确优先 Source, Bytes 当空处理" — 但调用方已经在
  334. // types.Blob 里强调过"二者并存请报错"; 为与 tx.BlobCommit 的"接受一个源"签名兼容, 此处
  335. // 直接用 Source, Bytes 忽略 (Source 不为 nil 时按 io.MultiSource 上报更彻底, 但保持现状)。
  336. func blobCarrier(b types.Blob) io.Reader {
  337. if b.Source != nil {
  338. return b.Source
  339. }
  340. return bytes.NewReader(b.Bytes)
  341. }
  342. // blobCompressOf / blobCompressOfString: 默认 CompressNone, 后续可在 schema 加列级配置
  343. // (例 `vrtx:"type:blob,compress:snappy"`) 时把这里的硬编码换成 fd.Compress 字段。
  344. func blobCompressOf(b []byte) types.FieldCompress { return types.CompressNone }
  345. func blobCompressOfString(s string) types.FieldCompress {
  346. return types.CompressNone
  347. }
  348. // readBlobBytes 按 ref 把 blob 内容整块读回内存 (供 []byte 载体使用)。
  349. //
  350. // 空 ref (FirstPageID == 0) 返回空切片而不是 nil: 载体是 []byte 的字段读回"空 blob"
  351. // 应当是 len==0 的非 nil 切片, 与 SQL 侧读到的空 BLOB 形态一致, 也避免调用方额外 nil-check。
  352. //
  353. // compress 取 CompressNone: 与写入侧 (blobCompressOf) 保持一致 —— 库不持久化压缩标志,
  354. // 两端必须约定同一个值, 否则解出来的是压缩后的字节流。
  355. func readBlobBytes(reader types.BlobReader, ref types.BlobRef) ([]byte, error) {
  356. if ref.FirstPageID == 0 && ref.TotalLen == 0 {
  357. return []byte{}, nil
  358. }
  359. if reader == nil {
  360. return nil, fmt.Errorf("vrtx: blob 列 (TotalLen=%d) 需要 blob reader (core.Table) 才能读回内容", ref.TotalLen)
  361. }
  362. rc, err := reader.ReadBlob(ref, types.CompressNone)
  363. if err != nil {
  364. return nil, fmt.Errorf("vrtx: 读取 blob 链失败: %w", err)
  365. }
  366. if rc == nil {
  367. return []byte{}, nil
  368. }
  369. defer rc.Close()
  370. data, err := io.ReadAll(rc)
  371. if err != nil {
  372. return nil, fmt.Errorf("vrtx: 读取 blob 内容失败: %w", err)
  373. }
  374. if data == nil {
  375. data = []byte{}
  376. }
  377. // 长度必须与 ref.TotalLen 严格一致: 链被截断 / 引用损坏时静默返回短数据,
  378. // 等于把损坏的 blob 当成合法内容交给上层 (core.BlobRead 同样按此契约返错)。
  379. if uint32(len(data)) != ref.TotalLen {
  380. return nil, fmt.Errorf("vrtx: 读取 blob 内容长度不符: ref.TotalLen=%d, 实读 %d 字节", ref.TotalLen, len(data))
  381. }
  382. return data, nil
  383. }
  384. // setFieldFromValue 将 core 返回值设置到结构体字段
  385. //
  386. // blobReader 只在 Blob 列 (val 是 types.BlobRef) 且载体是 []byte 时才用得上 —— ORM 的
  387. // Blob 列载体被约束成 []byte (见 types.go), 拿到的却是 8B 引用, 必须借它把内容读回来。
  388. func setFieldFromValue(target reflect.Value, val interface{}, fd FieldDef, blobReader types.BlobReader) error {
  389. if val == nil {
  390. return nil // NULL: 字段保持零值 (指针载体即 nil), 正是"没读到值"的表示
  391. }
  392. // 指针目标先落一层: 可空列的载体是 `*T`, 而解码值是 T —— 分配元素后往里写。
  393. // 集中在这里做, 下面那些 setXxxField 就不用各自认识指针 (它们只管元素类型)。
  394. if target.Kind() == reflect.Ptr {
  395. if target.IsNil() {
  396. target.Set(reflect.New(target.Type().Elem()))
  397. }
  398. target = target.Elem()
  399. }
  400. switch v := val.(type) {
  401. case uint64:
  402. setIntField(target, int64(v))
  403. case int64:
  404. setIntField(target, v)
  405. case int32:
  406. setIntField(target, int64(v))
  407. case int16:
  408. setIntField(target, int64(v))
  409. case int8:
  410. setIntField(target, int64(v))
  411. case uint8:
  412. setIntField(target, int64(v))
  413. case float64:
  414. setFloatField(target, v)
  415. case float32:
  416. setFloatField(target, float64(v))
  417. case bool:
  418. if target.Kind() == reflect.Bool {
  419. target.SetBool(v)
  420. }
  421. case []byte:
  422. setBytesField(target, v, fd)
  423. case types.Decimal:
  424. setDecimalField(target, v)
  425. case types.UUID:
  426. setUUIDField(target, v)
  427. case *big.Int:
  428. setBigIntField(target, v)
  429. case types.BlobRef:
  430. // 行内 8B 直接解出 ref. 三种载体:
  431. // - types.Blob: 填 ref 进结构体, 用户调 row.Cover.Open(table) 拿 io.ReadCloser
  432. // (流式, 适合大对象);
  433. // - []byte: 直接把内容读回内存 —— 这是 ORM 唯一允许的 Blob 列载体 (见 types.go),
  434. // 不读的话 []byte 字段永远是 nil, 写进去的东西读不回来;
  435. // - 其它 (自定义类型 / 自带 ref 的字段): 原样下传, 由 default 分支尽力赋值。
  436. switch {
  437. case target.Type() == reflect.TypeOf(types.Blob{}):
  438. b := types.Blob{FirstPageID: v.FirstPageID, TotalLen: v.TotalLen}
  439. if !b.Empty() {
  440. // Compress 没有持久化, 这里只能取零值 (CompressNone); 用户需要压缩一致性
  441. // 时, 应在表层配置 Compress 后整列落库, 这里不动它。详细见 types.Blob 注释。
  442. }
  443. target.Set(reflect.ValueOf(b))
  444. case target.Kind() == reflect.Slice && target.Type().Elem().Kind() == reflect.Uint8:
  445. data, err := readBlobBytes(blobReader, v)
  446. if err != nil {
  447. return err
  448. }
  449. target.SetBytes(data)
  450. default:
  451. rv := reflect.ValueOf(v)
  452. if rv.Type().AssignableTo(target.Type()) {
  453. target.Set(rv)
  454. } else if target.Kind() == reflect.Ptr && rv.Type().AssignableTo(target.Type().Elem()) {
  455. p := reflect.New(target.Type().Elem())
  456. p.Elem().Set(rv)
  457. target.Set(p)
  458. }
  459. }
  460. default:
  461. // 尝试直接设置 (同类型), 或填进同元素类型的指针字段
  462. // (struct 里写 `*types.Decimal` / `*big.Int` 时, 解码值是值类型)。
  463. rv := reflect.ValueOf(val)
  464. if !rv.IsValid() {
  465. return nil
  466. }
  467. switch {
  468. case rv.Type().AssignableTo(target.Type()):
  469. target.Set(rv)
  470. case target.Kind() == reflect.Ptr && rv.Type().AssignableTo(target.Type().Elem()):
  471. p := reflect.New(target.Type().Elem())
  472. p.Elem().Set(rv)
  473. target.Set(p)
  474. }
  475. }
  476. return nil
  477. }
  478. // setDecimalField 把解码出来的 Decimal 落到结构体字段。
  479. // 只做【无损】转换: 目标是有符号/无符号整数时要求 scale 为 0, 否则不写 —— 由调用方
  480. // 决定是要 string 还是 float 载体, 而不是在这里悄悄舍入。
  481. func setDecimalField(target reflect.Value, d types.Decimal) {
  482. switch {
  483. case target.Type() == reflect.TypeOf(types.Decimal{}):
  484. target.Set(reflect.ValueOf(d))
  485. case target.Kind() == reflect.Ptr && target.Type().Elem() == reflect.TypeOf(types.Decimal{}):
  486. p := reflect.New(target.Type().Elem())
  487. p.Elem().Set(reflect.ValueOf(d))
  488. target.Set(p)
  489. case target.Kind() == reflect.String:
  490. target.SetString(d.String())
  491. case target.Kind() == reflect.Float32, target.Kind() == reflect.Float64:
  492. target.SetFloat(d.Float64())
  493. case d.Scale() == 0:
  494. coef := d.Coefficient()
  495. switch target.Kind() {
  496. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  497. if coef.IsInt64() {
  498. target.SetInt(coef.Int64())
  499. }
  500. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  501. if coef.IsUint64() {
  502. target.SetUint(coef.Uint64())
  503. }
  504. }
  505. }
  506. }
  507. // setUUIDField 把解码出来的 UUID 落到结构体字段 (UUID / string / [16]byte / []byte)。
  508. func setUUIDField(target reflect.Value, u types.UUID) {
  509. switch {
  510. case target.Type() == reflect.TypeOf(types.UUID{}):
  511. target.Set(reflect.ValueOf(u))
  512. case target.Kind() == reflect.Ptr && target.Type().Elem() == reflect.TypeOf(types.UUID{}):
  513. p := reflect.New(target.Type().Elem())
  514. p.Elem().Set(reflect.ValueOf(u))
  515. target.Set(p)
  516. case target.Kind() == reflect.String:
  517. target.SetString(u.String())
  518. case target.Kind() == reflect.Array && target.Len() == types.UUIDSize && target.Type().Elem().Kind() == reflect.Uint8:
  519. reflect.Copy(target, reflect.ValueOf(u[:]))
  520. case target.Kind() == reflect.Slice && target.Type().Elem().Kind() == reflect.Uint8:
  521. target.SetBytes(append([]byte(nil), u[:]...))
  522. }
  523. }
  524. // setBigIntField 把解码出来的 *big.Int 落到结构体字段 (big.Int / *big.Int / string / 整数)。
  525. func setBigIntField(target reflect.Value, v *big.Int) {
  526. if v == nil {
  527. v = new(big.Int)
  528. }
  529. switch {
  530. case target.Type() == reflect.TypeOf(big.Int{}):
  531. target.Set(reflect.ValueOf(*new(big.Int).Set(v)))
  532. case target.Type() == reflect.TypeOf(&big.Int{}):
  533. target.Set(reflect.ValueOf(new(big.Int).Set(v)))
  534. case target.Type() == reflect.TypeOf(types.Decimal{}):
  535. if d, err := types.NewDecimal(v, 0); err == nil {
  536. target.Set(reflect.ValueOf(d))
  537. }
  538. case target.Kind() == reflect.String:
  539. target.SetString(v.String())
  540. case target.Kind() == reflect.Int, target.Kind() == reflect.Int8,
  541. target.Kind() == reflect.Int16, target.Kind() == reflect.Int32, target.Kind() == reflect.Int64:
  542. if v.IsInt64() {
  543. target.SetInt(v.Int64())
  544. }
  545. case target.Kind() == reflect.Uint, target.Kind() == reflect.Uint8,
  546. target.Kind() == reflect.Uint16, target.Kind() == reflect.Uint32, target.Kind() == reflect.Uint64:
  547. if v.IsUint64() {
  548. target.SetUint(v.Uint64())
  549. }
  550. }
  551. }
  552. func setIntField(target reflect.Value, val int64) {
  553. switch target.Kind() {
  554. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  555. target.SetInt(val)
  556. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  557. target.SetUint(uint64(val))
  558. case reflect.Float32, reflect.Float64:
  559. target.SetFloat(float64(val))
  560. case reflect.Bool:
  561. target.SetBool(val != 0)
  562. }
  563. }
  564. func setFloatField(target reflect.Value, val float64) {
  565. switch target.Kind() {
  566. case reflect.Float32, reflect.Float64:
  567. target.SetFloat(val)
  568. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  569. target.SetInt(int64(val))
  570. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  571. target.SetUint(uint64(val))
  572. }
  573. }
  574. func setBytesField(target reflect.Value, val []byte, fd FieldDef) {
  575. switch target.Kind() {
  576. case reflect.String:
  577. // 截断到第一个 null 字节
  578. s := string(val)
  579. for i, c := range s {
  580. if c == 0 {
  581. s = s[:i]
  582. break
  583. }
  584. }
  585. target.SetString(s)
  586. case reflect.Slice:
  587. if target.Type().Elem().Kind() == reflect.Uint8 {
  588. target.SetBytes(val)
  589. }
  590. }
  591. }
  592. // ===== 类型转换辅助函数 =====
  593. // isNilPointerValue 判断反射值是否为 nil 指针 / nil 接口 (nil 切片不算 —— 空值 ≠ NULL)。
  594. func isNilPointerValue(v reflect.Value) bool {
  595. switch v.Kind() {
  596. case reflect.Ptr, reflect.Interface:
  597. return v.IsNil()
  598. }
  599. return false
  600. }
  601. func toUint64(v interface{}) uint64 {
  602. switch val := v.(type) {
  603. case uint64:
  604. return val
  605. case int64:
  606. return uint64(val)
  607. case int:
  608. return uint64(val)
  609. case int32:
  610. return uint64(val)
  611. case uint32:
  612. return uint64(val)
  613. case int16:
  614. return uint64(val)
  615. case uint16:
  616. return uint64(val)
  617. case int8:
  618. return uint64(val)
  619. case uint8:
  620. return uint64(val)
  621. case float64:
  622. return uint64(val)
  623. case float32:
  624. return uint64(val)
  625. case bool:
  626. if val {
  627. return 1
  628. }
  629. return 0
  630. default:
  631. rv := reflect.ValueOf(v)
  632. if rv.CanUint() {
  633. return rv.Uint()
  634. }
  635. if rv.CanInt() {
  636. return uint64(rv.Int())
  637. }
  638. return 0
  639. }
  640. }
  641. // toInt64 把任意数值/反射值转成 int64, 供有符号整数列 (FieldType_Int*) 使用。
  642. //
  643. // 不走 toUint64 再强转: 对负整数那条路是"绕一圈无符号", 靠低位截断侥幸正确;
  644. // 但对负浮点是未定义行为 (Go 规范: 负浮点转无符号数结果实现相关)。直接按有符号取,
  645. // 语义明确, 且 toInt8/16/32 也一并收敛到这里。
  646. func toInt64(v interface{}) int64 {
  647. switch val := v.(type) {
  648. case int64:
  649. return val
  650. case int:
  651. return int64(val)
  652. case int32:
  653. return int64(val)
  654. case int16:
  655. return int64(val)
  656. case int8:
  657. return int64(val)
  658. case uint64:
  659. return int64(val)
  660. case uint:
  661. return int64(val)
  662. case uint32:
  663. return int64(val)
  664. case uint16:
  665. return int64(val)
  666. case uint8:
  667. return int64(val)
  668. case float64:
  669. return int64(val)
  670. case float32:
  671. return int64(val)
  672. case bool:
  673. if val {
  674. return 1
  675. }
  676. return 0
  677. default:
  678. rv := reflect.ValueOf(v)
  679. if !rv.IsValid() {
  680. return 0
  681. }
  682. switch rv.Kind() {
  683. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  684. return rv.Int()
  685. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  686. return int64(rv.Uint())
  687. case reflect.Float32, reflect.Float64:
  688. return int64(rv.Float())
  689. case reflect.Bool:
  690. if rv.Bool() {
  691. return 1
  692. }
  693. }
  694. return 0
  695. }
  696. }
  697. func toInt8(v interface{}) int8 { return int8(toInt64(v)) }
  698. func toInt16(v interface{}) int16 { return int16(toInt64(v)) }
  699. func toInt32(v interface{}) int32 { return int32(toInt64(v)) }
  700. // toFloatVal 把任意数值/反射值转成 float64, 供浮点列写入使用。
  701. // 注意这里不能经由 toUint64: 那会把小数部分先砍掉, 正是要避免的截断。
  702. func toFloatVal(v interface{}) float64 {
  703. switch val := v.(type) {
  704. case float64:
  705. return val
  706. case float32:
  707. return float64(val)
  708. case int64:
  709. return float64(val)
  710. case int:
  711. return float64(val)
  712. case int32:
  713. return float64(val)
  714. case uint32:
  715. return float64(val)
  716. case int16:
  717. return float64(val)
  718. case uint16:
  719. return float64(val)
  720. case int8:
  721. return float64(val)
  722. case uint8:
  723. return float64(val)
  724. case uint64:
  725. return float64(val)
  726. default:
  727. rv := reflect.ValueOf(v)
  728. if !rv.IsValid() {
  729. return 0
  730. }
  731. switch rv.Kind() {
  732. case reflect.Float32, reflect.Float64:
  733. return rv.Float()
  734. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  735. return float64(rv.Int())
  736. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  737. return float64(rv.Uint())
  738. case reflect.Bool:
  739. if rv.Bool() {
  740. return 1
  741. }
  742. }
  743. return 0
  744. }
  745. }
  746. func toFixedBytes(v interface{}, size int) []byte {
  747. buf := make([]byte, size)
  748. switch val := v.(type) {
  749. case string:
  750. copy(buf, val)
  751. case []byte:
  752. copy(buf, val)
  753. default:
  754. // 数值类型: BigEndian 编码
  755. rv := reflect.ValueOf(v)
  756. if rv.CanUint() {
  757. binary.BigEndian.PutUint64(buf, rv.Uint())
  758. } else if rv.CanInt() {
  759. binary.BigEndian.PutUint64(buf, uint64(rv.Int()))
  760. }
  761. }
  762. return buf
  763. }
  764. func toBytes(v interface{}) []byte {
  765. switch val := v.(type) {
  766. case []byte:
  767. return val
  768. case string:
  769. return []byte(val)
  770. default:
  771. return nil
  772. }
  773. }
  774. // getPKValue 从结构体中提取主键值
  775. // 负数直接拒绝: 引擎的主键号是无符号 uint64, int64 主键填负数会被静默转成一个极大的号,
  776. // 之后按自己写的值既查不到也删不掉 —— 报错比留下查不到的行好。
  777. func getPKValue(obj interface{}, model *ModelInfo) (uint64, error) {
  778. // PKInStruct 现在恒为 true (表必须内嵌基类, 键列总能对应到结构体字段)。
  779. // 保留这个分支作为兜底: 万一将来又出现"键列不在结构体里"的模型, 让它退回
  780. // "主键填 0 → 由引擎分配"的旧行为, 而不是去取一个不存在的字段。
  781. if !model.PKInStruct {
  782. return 0, nil // PK 不在结构体中,返回 0 让 core 自动分配
  783. }
  784. v := reflect.ValueOf(obj)
  785. if v.Kind() == reflect.Ptr {
  786. v = v.Elem()
  787. }
  788. pkDef := model.AllFields[model.PKIndex]
  789. fv := fieldByModelPath(v, pkDef, model.StructType)
  790. if !fv.IsValid() {
  791. return 0, nil
  792. }
  793. if fv.CanInt() && fv.Int() < 0 {
  794. return 0, fmt.Errorf("%w: 字段 %s = %d 为负数, 主键必须是非负整数",
  795. ErrInvalidPrimaryKey, pkDef.Name, fv.Int())
  796. }
  797. return toUint64(fv.Interface()), nil
  798. }
  799. // setPKValue 设置结构体的主键值
  800. func setPKValue(obj interface{}, model *ModelInfo, pk uint64) {
  801. // 同 getPKValue: PKInStruct 恒为 true, 这里是防御性兜底。
  802. if !model.PKInStruct {
  803. return // PK 不在结构体中,无法回写
  804. }
  805. v := reflect.ValueOf(obj)
  806. if v.Kind() == reflect.Ptr {
  807. v = v.Elem()
  808. }
  809. pkDef := model.AllFields[model.PKIndex]
  810. fv := fieldByModelPath(v, pkDef, model.StructType)
  811. if fv.IsValid() && fv.CanSet() {
  812. // 走 setIntField 而不是 SetUint: 自定义主键可以是 int64,
  813. // 而在有符号整数上调用 SetUint 会 panic。
  814. setIntField(fv, int64(pk))
  815. }
  816. }
  817. // zeroValue 返回字段类型的零值
  818. func zeroValue(fd FieldDef) interface{} {
  819. switch fd.FieldType {
  820. case types.FieldType_Uint8:
  821. return uint8(0)
  822. case types.FieldType_Uint16:
  823. return int16(0)
  824. case types.FieldType_Uint32:
  825. return int32(0)
  826. case types.FieldType_Uint64:
  827. return uint64(0)
  828. case types.FieldType_Int8:
  829. return int8(0)
  830. case types.FieldType_Int16:
  831. return int16(0)
  832. case types.FieldType_Int32:
  833. return int32(0)
  834. case types.FieldType_Int64:
  835. return int64(0)
  836. case types.FieldType_Float64:
  837. return float64(0)
  838. // ===== 扩展类型: 零值必须与"标准解码载体"同类型, 否则写入时 EncodeValue 认不出来 =====
  839. case types.FieldType_Bool:
  840. return false
  841. case types.FieldType_Float32:
  842. return float32(0)
  843. case types.FieldType_Decimal:
  844. return types.Decimal{}
  845. case types.FieldType_UUID:
  846. return types.UUID{}
  847. case types.FieldType_Year:
  848. return int16(0)
  849. case types.FieldType_Int128:
  850. return new(big.Int)
  851. case types.FieldType_Blob:
  852. return []byte{}
  853. default:
  854. // 动态列的"值"就是字节内容本身: 行内那 6 字节堆引用由引擎写入时生成,
  855. // 不能当成值送进去 (旧写法送 6 个零字节, 落盘是一条 6 字节的垃圾内容)。
  856. if types.IsDynamic(fd.FieldType) {
  857. return []byte{}
  858. }
  859. // 定长字符串列的零值 = 该列宽度个零字节。宽度必须取列声明 (fd.Width()),
  860. // 不是类型默认: `maxlen:1000` 的列按 256 补零会让 EncodeValue 的长度校验失败,
  861. // "写零值"这条路直接报错。
  862. if size := int(fd.Width()); size > 0 {
  863. return make([]byte, size)
  864. }
  865. return []byte{}
  866. }
  867. }