convert.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. package vrtxsql
  2. // 值与类型的双向翻译:
  3. // - SQL 字面量/driver.Value → 引擎列类型 (写入路径)
  4. // - 引擎值 → driver.Value (结果集路径, database/sql 只接受基础类型)
  5. // - SQL 类型名 → types.FieldInfo (CREATE TABLE 路径)
  6. import (
  7. "database/sql/driver"
  8. "fmt"
  9. "math"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "git.ycl.pub/yl32940/TsDB2/DB/core"
  14. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  15. )
  16. // =============================================================================
  17. // driver.Value → 引擎值 (按列类型)
  18. // =============================================================================
  19. func driverToEngineValue(fi *types.FieldInfo, v driver.Value) (interface{}, error) {
  20. if v == nil {
  21. return nil, nil // NULL: 由引擎按 FlagNullable 裁决
  22. }
  23. switch fi.FieldType {
  24. case types.FieldType_DateTime:
  25. // time.Time 原样 (引擎编码层转毫秒); 数值已是毫秒; 字符串走字面量解析,
  26. // 其中零时间 (0001-01-01...) 解析出 nil → 返回 (nil, nil) = NULL,
  27. // 与 buildFieldValue 的 NULL 语义汇合 (软删除 UPDATE SET deleted_at=零时间 ⇒ NULL)。
  28. switch t := v.(type) {
  29. case time.Time:
  30. return t, nil
  31. case int64:
  32. if t < 0 {
  33. return nil, fmt.Errorf("时间戳不能为负: %d", t)
  34. }
  35. return t, nil // 已是毫秒
  36. case uint64:
  37. return t, nil // 已是毫秒
  38. case float64:
  39. if t < 0 {
  40. return nil, fmt.Errorf("时间戳不能为负: %v", t)
  41. }
  42. return int64(t), nil // 已是毫秒
  43. case string:
  44. return parseDateTimeLiteral(t)
  45. case []byte:
  46. return parseDateTimeLiteral(string(t))
  47. }
  48. return nil, typeMismatch(fi, v)
  49. case types.FieldType_Uint64:
  50. // 旧版驱动把 DATETIME 建成 Uint64 列: 整数之外宽容接受 time.Time /
  51. // 时间文本 / 毫秒串 (toDateTimeMillis 统一按毫秒), 保证老表时间读写不回退。
  52. switch v.(type) {
  53. case time.Time, string, []byte:
  54. return toDateTimeMillis(v)
  55. }
  56. return toInt64(v)
  57. case types.FieldType_Int64,
  58. types.FieldType_Uint32, types.FieldType_Int32,
  59. types.FieldType_Uint16, types.FieldType_Int16,
  60. types.FieldType_Uint8, types.FieldType_Int8,
  61. types.FieldType_Year:
  62. return toInt64(v)
  63. case types.FieldType_Float64, types.FieldType_Float32:
  64. return toFloat64(v)
  65. case types.FieldType_Bool:
  66. switch t := v.(type) {
  67. case bool:
  68. return t, nil
  69. case int64:
  70. return t != 0, nil
  71. case string:
  72. return strings.EqualFold(t, "true") || t == "1", nil
  73. }
  74. return nil, typeMismatch(fi, v)
  75. case types.FieldType_String:
  76. switch t := v.(type) {
  77. case string:
  78. return t, nil
  79. case []byte:
  80. return string(t), nil
  81. }
  82. return nil, typeMismatch(fi, v)
  83. case types.FieldType_Dynamicbyte:
  84. switch t := v.(type) {
  85. case []byte:
  86. return t, nil
  87. case string:
  88. return []byte(t), nil
  89. }
  90. return nil, typeMismatch(fi, v)
  91. case types.FieldType_Decimal:
  92. switch t := v.(type) {
  93. case string:
  94. return types.MustParseDecimal(t), nil
  95. case []byte:
  96. return types.MustParseDecimal(string(t)), nil
  97. case float64:
  98. return types.MustParseDecimal(strconv.FormatFloat(t, 'f', -1, 64)), nil
  99. }
  100. return nil, typeMismatch(fi, v)
  101. case types.FieldType_UUID:
  102. switch t := v.(type) {
  103. case string:
  104. return types.MustParseUUID(t), nil // 若存在解析入口则用之
  105. case []byte:
  106. if len(t) == 16 {
  107. var u [16]byte
  108. copy(u[:], t)
  109. return u, nil
  110. }
  111. return types.MustParseUUID(string(t)), nil
  112. }
  113. return nil, typeMismatch(fi, v)
  114. case types.FieldType_Blob:
  115. switch t := v.(type) {
  116. case []byte:
  117. return t, nil
  118. case string:
  119. return []byte(t), nil
  120. }
  121. return nil, typeMismatch(fi, v)
  122. }
  123. return nil, typeMismatch(fi, v)
  124. }
  125. func typeMismatch(fi *types.FieldInfo, v driver.Value) error {
  126. return fmt.Errorf("值类型 %T 与列 %q 的类型 %d 不匹配", v, fi.FieldName, fi.FieldType)
  127. }
  128. func toInt64(v driver.Value) (interface{}, error) {
  129. switch t := v.(type) {
  130. case int64:
  131. return t, nil
  132. case float64:
  133. return int64(t), nil
  134. case bool:
  135. if t {
  136. return int64(1), nil
  137. }
  138. return int64(0), nil
  139. case string:
  140. n, err := strconv.ParseInt(strings.TrimSpace(t), 10, 64)
  141. if err == nil {
  142. return n, nil
  143. }
  144. f, ferr := strconv.ParseFloat(strings.TrimSpace(t), 64)
  145. if ferr == nil {
  146. return int64(f), nil
  147. }
  148. case []byte:
  149. return toInt64(string(t))
  150. case time.Time:
  151. return int64(timeToMillis(t)), nil // 时间列: time.Time → 毫秒
  152. }
  153. return nil, fmt.Errorf("无法把 %T 转成整数", v)
  154. }
  155. func toFloat64(v driver.Value) (interface{}, error) {
  156. switch t := v.(type) {
  157. case float64:
  158. return t, nil
  159. case int64:
  160. return float64(t), nil
  161. case string:
  162. f, err := strconv.ParseFloat(strings.TrimSpace(t), 64)
  163. if err == nil {
  164. return f, nil
  165. }
  166. case []byte:
  167. return toFloat64(string(t))
  168. }
  169. return nil, fmt.Errorf("无法把 %T 转成浮点", v)
  170. }
  171. // =============================================================================
  172. // 字面量 → 引擎值 (WHERE/VALUES 里的纯文本数字/字符串)
  173. // =============================================================================
  174. // parseLiteralAsType 按列的实际类型解释字面量文本。数字字面量到整型列按 int64,
  175. // 到浮点按 float64; 字符串字面量按列类型解析 (数字字符串转数值, 其余原样)。
  176. func parseLiteralAsType(fi *types.FieldInfo, s string) (interface{}, error) {
  177. switch fi.FieldType {
  178. case types.FieldType_Float64, types.FieldType_Float32:
  179. if f, err := strconv.ParseFloat(s, 64); err == nil {
  180. return f, nil
  181. }
  182. case types.FieldType_Uint64:
  183. // 整数优先; 兼容旧版 DATETIME 建的 Uint64 列: 时间文本/毫秒串按毫秒解释。
  184. if n, err := strconv.ParseInt(s, 10, 64); err == nil {
  185. return n, nil
  186. }
  187. if f, ferr := strconv.ParseFloat(s, 64); ferr == nil {
  188. return int64(f), nil
  189. }
  190. if ms, terr := parseDateTimeText(s); terr == nil {
  191. return ms, nil
  192. }
  193. case types.FieldType_Int64,
  194. types.FieldType_Uint32, types.FieldType_Int32,
  195. types.FieldType_Uint16, types.FieldType_Int16,
  196. types.FieldType_Uint8, types.FieldType_Int8,
  197. types.FieldType_Year:
  198. if n, err := strconv.ParseInt(s, 10, 64); err == nil {
  199. return n, nil
  200. }
  201. if f, ferr := strconv.ParseFloat(s, 64); ferr == nil {
  202. return int64(f), nil
  203. }
  204. case types.FieldType_Bool:
  205. if b, err := strconv.ParseBool(s); err == nil {
  206. return b, nil
  207. }
  208. case types.FieldType_Decimal:
  209. return types.MustParseDecimal(s), nil
  210. case types.FieldType_DateTime:
  211. return parseDateTimeLiteral(s)
  212. default:
  213. // 字符串/动态列: 原样
  214. return s, nil
  215. }
  216. return nil, fmt.Errorf("字面量 %q 无法解释为列 %q 的类型 %d", s, fi.FieldName, fi.FieldType)
  217. }
  218. // =============================================================================
  219. // 引擎值 → driver.Value
  220. // =============================================================================
  221. // blobReaderOf 绑定某张表的 BlobRef 物化入口: 行内 8B 链引用 → 内容字节。
  222. //
  223. // compress 固定 CompressNone, 与写入侧严格一致 —— 引擎写路径 (Table.blobFieldRef)
  224. // 把驱动/migrate 写入的 []byte / string 内容按 CompressNone 落链 (FieldInfo 不持久化
  225. // 压缩标志, 压缩只是 Blob 载体 types.Blob 的运行时参数; 库内两处读回 —
  226. // DB.readBlobBytes 与 migrate 的 VRTX.Scan —— 都是这个取值)。空引用 (空内容, 非
  227. // NULL —— NULL 走行内位图、根本不会以 BlobRef 形态出现) 归一成空切片, Scan 到
  228. // []byte 得到 len==0 而不是 nil。
  229. func blobReaderOf(tbl *core.Table) func(types.BlobRef) ([]byte, error) {
  230. return func(ref types.BlobRef) ([]byte, error) {
  231. data, err := tbl.BlobRead(ref, types.CompressNone)
  232. if err != nil {
  233. return nil, err
  234. }
  235. if data == nil {
  236. return []byte{}, nil
  237. }
  238. return data, nil
  239. }
  240. }
  241. func fieldValueToDriver(v interface{}) (driver.Value, error) {
  242. switch t := v.(type) {
  243. case nil:
  244. return nil, nil
  245. case int64:
  246. return t, nil
  247. case int:
  248. return int64(t), nil
  249. case uint64:
  250. if t > math.MaxInt64 {
  251. return nil, fmt.Errorf("uint64 值 %d 超出 database/sql 的 int64 表示范围", t)
  252. }
  253. return int64(t), nil
  254. case uint32:
  255. return int64(t), nil
  256. case uint16:
  257. return int64(t), nil
  258. case uint8:
  259. return int64(t), nil
  260. case float64:
  261. return t, nil
  262. case float32:
  263. return float64(t), nil
  264. case bool:
  265. return t, nil
  266. case string:
  267. return []byte(t), nil // 字符串统一以 []byte 出 (database/sql Scan 兼容)
  268. case []byte:
  269. return t, nil
  270. case time.Time:
  271. return t, nil
  272. case types.BlobRef:
  273. // Blob 列行内只有 8B 链引用; 结果集物化由持有表句柄的路径经 blobReaderOf
  274. // 解引用 (流式 rows.start / JOIN scanJoinTable, 见 driver.go / join.go) ——
  275. // 这一层没有读取入口。仍带着引用走到这里 (聚合 MIN/MAX 命中 blob 列等)
  276. // 只能明确报错, 不能静默吐出引用结构或 fmt.Sprint 的杂串。
  277. return nil, fmt.Errorf("BLOB 列的值 (引用 %v) 没有读取入口, 聚合函数不支持 BLOB 列", t)
  278. default:
  279. // Decimal / UUID 等其余类型: 文本化出 (Scan 到 string 可用)
  280. return []byte(fmt.Sprint(v)), nil
  281. }
  282. }
  283. // fieldValueToDriverTyped 同 fieldValueToDriver, 但按列类型做语义转换:
  284. // DateTime 列把 uint64 毫秒还原成 time.Time —— 与写入 time.Time 对称。
  285. func fieldValueToDriverTyped(ft types.FieldType, v interface{}) (driver.Value, error) {
  286. if ft == types.FieldType_DateTime {
  287. switch x := v.(type) {
  288. case nil:
  289. return nil, nil
  290. case time.Time:
  291. return x, nil
  292. case uint64:
  293. return millisToTime(x), nil
  294. case int64:
  295. if x < 0 {
  296. return nil, fmt.Errorf("时间戳不能为负: %d", x)
  297. }
  298. return millisToTime(uint64(x)), nil
  299. }
  300. return nil, fmt.Errorf("无法把 %T 作为日期时间返回", v)
  301. }
  302. return fieldValueToDriver(v)
  303. }
  304. // =============================================================================
  305. // SQL 类型名 → types.FieldInfo (CREATE TABLE)
  306. // =============================================================================
  307. // sqlTypeToFieldInfo 映射 ORM 常见列类型。未覆盖的类型返回明确错误。
  308. func sqlTypeToFieldInfo(c colDef) (types.FieldInfo, error) {
  309. fi := types.FieldInfo{FieldName: []byte(c.name)}
  310. if !c.notNull {
  311. fi.Flag |= types.FlagNullable // SQL 默认可空
  312. }
  313. name := c.typeName
  314. switch name {
  315. case "BIGINT", "INT8":
  316. fi.FieldType = types.FieldType_Int64
  317. case "INT", "INTEGER", "INT4", "MEDIUMINT":
  318. fi.FieldType = types.FieldType_Int32
  319. case "SMALLINT", "INT2":
  320. fi.FieldType = types.FieldType_Int16
  321. case "TINYINT", "INT1":
  322. fi.FieldType = types.FieldType_Int8
  323. case "BIGINT UNSIGNED":
  324. fi.FieldType = types.FieldType_Uint64
  325. case "INT UNSIGNED", "INTEGER UNSIGNED":
  326. fi.FieldType = types.FieldType_Uint32
  327. case "DOUBLE", "DOUBLE PRECISION", "REAL":
  328. fi.FieldType = types.FieldType_Float64
  329. case "FLOAT":
  330. fi.FieldType = types.FieldType_Float32
  331. case "BOOL", "BOOLEAN":
  332. fi.FieldType = types.FieldType_Bool
  333. case "VARCHAR", "CHAR", "CHARACTER":
  334. w := 32
  335. if c.arg > 0 {
  336. w = c.arg
  337. }
  338. if w > 2048 {
  339. return fi, fmt.Errorf("VARCHAR(%d) 超过引擎定长字符串上限 2048, 请用 TEXT (动态列)", w)
  340. }
  341. fi.FieldType = types.FieldType_String
  342. fi.Flag |= types.WidthCodeFor(w)
  343. case "TEXT", "LONGTEXT", "MEDIUMTEXT":
  344. fi.FieldType = types.FieldType_Dynamicbyte
  345. case "BLOB", "LONGBLOB", "MEDIUMBLOB", "BINARY", "VARBINARY":
  346. fi.FieldType = types.FieldType_Blob
  347. case "DECIMAL", "NUMERIC":
  348. fi.FieldType = types.FieldType_Decimal
  349. if c.arg >= 0 {
  350. fi.Flag |= byte(c.arg) // DECIMAL(p,s) 的 s 落 Flag 低 5 位
  351. }
  352. case "DATETIME", "TIMESTAMP":
  353. fi.FieldType = types.FieldType_DateTime // 行内 8B 毫秒, 结果路径还原 time.Time
  354. case "UUID":
  355. fi.FieldType = types.FieldType_UUID
  356. default:
  357. return fi, fmt.Errorf("不支持的列类型 %q", c.typeName)
  358. }
  359. return fi, nil
  360. }
  361. // =============================================================================
  362. // DateTime: driver 值 / 文本 → uint64 毫秒
  363. // =============================================================================
  364. // dateTimeLiteralLayouts parseDateTimeLiteral 尝试的时间文本布局 (按顺序;
  365. // 无时区者按本地时区解释)。
  366. var dateTimeLiteralLayouts = []string{
  367. "2006-01-02 15:04:05.999999999",
  368. "2006-01-02 15:04:05",
  369. "2006-01-02T15:04:05.999999999",
  370. "2006-01-02",
  371. }
  372. // parseDateTimeLiteral 解析 SQL 文本里的日期时间字面量。GORM 会把 time.Time
  373. // 族字段的值【内联成 SQL 字符串字面量】而不是 ? 参数, 零值 gorm.DeletedAt
  374. // 更是被序列化成 "{0001-01-01 00:00:00 +0000 UTC false}" 这样的垃圾串。
  375. //
  376. // 约定:
  377. // - 剥掉首尾空白与 {} 包裹;
  378. // - 以 "0001-01-01" 开头 = 零时间, 返回 (nil, nil) → 调用方按 NULL 处理
  379. // (GORM 软删除的未删除态正是零 DeletedAt ⇔ deleted_at IS NULL);
  380. // - 其余按 dateTimeLiteralLayouts 解析, 成功返回 time.Time (引擎编码层
  381. // 负责 time.Time → uint64 毫秒);
  382. // - 全部失败返回含原文的明确错误。
  383. func parseDateTimeLiteral(s string) (interface{}, error) {
  384. t := strings.TrimSpace(s)
  385. if len(t) >= 2 && t[0] == '{' && t[len(t)-1] == '}' {
  386. t = strings.TrimSpace(t[1 : len(t)-1])
  387. }
  388. if strings.HasPrefix(t, "0001-01-01") {
  389. return nil, nil // 零时间 = NULL
  390. }
  391. for _, layout := range dateTimeLiteralLayouts {
  392. if ts, err := time.ParseInLocation(layout, t, time.Local); err == nil {
  393. return ts, nil
  394. }
  395. }
  396. return nil, fmt.Errorf("无法把 %q 解析为日期时间字面量 (支持 'YYYY-MM-DD HH:MM:SS[.小数]'、'YYYY-MM-DDThh:mm:ss[.小数]'、'YYYY-MM-DD'; 0001-01-01 零时间视为 NULL)", s)
  397. }
  398. // timeLayouts 接受的时间文本格式 (按尝试顺序; 无时区者按本地时区解释)。
  399. var timeLayouts = []string{
  400. time.RFC3339Nano,
  401. time.RFC3339,
  402. "2006-01-02 15:04:05.999999999",
  403. "2006-01-02 15:04:05.999",
  404. "2006-01-02 15:04:05",
  405. "2006-01-02T15:04:05.999999999",
  406. "2006-01-02T15:04:05",
  407. "2006-01-02 15:04",
  408. "2006-01-02",
  409. }
  410. // parseTimeFlexible 解析常见时间文本, 成功返回 time.Time。
  411. func parseTimeFlexible(s string) (time.Time, bool) {
  412. t := strings.TrimSpace(s)
  413. for _, layout := range timeLayouts {
  414. if ts, err := time.ParseInLocation(layout, t, time.Local); err == nil {
  415. return ts, true
  416. }
  417. }
  418. return time.Time{}, false
  419. }
  420. // parseDateTimeText 把时间文本或纯毫秒数字解析成引擎 uint64 毫秒。
  421. func parseDateTimeText(s string) (interface{}, error) {
  422. t := strings.TrimSpace(s)
  423. if ts, ok := parseTimeFlexible(t); ok {
  424. return uint64(timeToMillis(ts)), nil
  425. }
  426. if n, err := strconv.ParseInt(t, 10, 64); err == nil {
  427. if n < 0 {
  428. return nil, fmt.Errorf("时间戳不能为负: %d", n)
  429. }
  430. return uint64(n), nil
  431. }
  432. return nil, fmt.Errorf("无法把 %q 解析为日期时间 (支持 'YYYY-MM-DD HH:MM:SS'、RFC3339 或毫秒数字)", s)
  433. }
  434. // toDateTimeMillis 把 driver 参数转成引擎 uint64 毫秒 (time.Time/数字/文本)。
  435. func toDateTimeMillis(v driver.Value) (interface{}, error) {
  436. if v == nil {
  437. return nil, nil
  438. }
  439. switch t := v.(type) {
  440. case time.Time:
  441. return uint64(timeToMillis(t)), nil
  442. case int64:
  443. if t < 0 {
  444. return nil, fmt.Errorf("时间戳不能为负: %d", t)
  445. }
  446. return uint64(t), nil
  447. case float64:
  448. if t < 0 {
  449. return nil, fmt.Errorf("时间戳不能为负: %v", t)
  450. }
  451. return uint64(t), nil
  452. case string:
  453. return parseDateTimeText(t)
  454. case []byte:
  455. return parseDateTimeText(string(t))
  456. }
  457. return nil, fmt.Errorf("无法把 %T 转成日期时间", v)
  458. }