convert.go 14 KB

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