driver.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. package vrtxsql
  2. // database/sql 驱动壳: 连接注册表 (同路径共享一个引擎)、
  3. // Conn/Tx/Stmt/Rows 适配。引擎是一写多读模型:
  4. // - shared.sem 容量 16: 允许多读者并行进入引擎; 写操作也走同一条通道,
  5. // 但 core.accMu.Lock() 会把并发写排他化 (Begin/Commit/DDL 持写锁)
  6. // - 锁获取尊重 ctx —— 排队等锁阶段可被超时/取消中断
  7. // - SELECT 结果集流式返回 (worker 回调 + channel), Close 前持续持锁
  8. //
  9. // 调用方建议 SetMaxOpenConns(16) (≥ semaphore 容量), 否则并发读会在
  10. // sql.DB 连接池层被串行化, 引擎内部的 RLock 优势发挥不出来。
  11. import (
  12. "context"
  13. "database/sql"
  14. "database/sql/driver"
  15. "errors"
  16. "fmt"
  17. "io"
  18. "net/url"
  19. "reflect"
  20. "strconv"
  21. "strings"
  22. "sync"
  23. "time"
  24. "git.ycl.pub/yl32940/TsDB2/DB/core"
  25. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  26. )
  27. func init() {
  28. sql.Register("vrtx", &vrtxDriver{})
  29. }
  30. // vrtxDriver 实现 driver.Driver。
  31. type vrtxDriver struct{}
  32. // registry 同一路径 (DSN) 的所有连接共享同一个 *core.DB —— 引擎的文件锁与
  33. // 单写者语义不允许一个库被打开成多个实例。
  34. var registry = struct {
  35. sync.Mutex
  36. m map[string]*shared
  37. }{m: make(map[string]*shared)}
  38. type shared struct {
  39. db *core.DB
  40. dsn string
  41. sem chan struct{} // 容量16: 允许多个读者并行; Begin/Commit 的写锁由 core.accMu 排他保证
  42. refs int
  43. }
  44. // lock 获取串行锁; 排队期间尊重 ctx (超时/取消返回 ctx.Err)。
  45. func (s *shared) lock(ctx context.Context) error {
  46. if ctx == nil {
  47. ctx = context.Background()
  48. }
  49. select {
  50. case s.sem <- struct{}{}:
  51. return nil
  52. case <-ctx.Done():
  53. return ctx.Err()
  54. }
  55. }
  56. // unlock 释放串行锁 (非严格: 未持有时不阻塞、不 panic)。
  57. func (s *shared) unlock() {
  58. select {
  59. case <-s.sem:
  60. default:
  61. }
  62. }
  63. // dsnConfig 是 DSN 解析结果: 文件路径 + 打开选项。
  64. type dsnConfig struct {
  65. path string
  66. readOnly bool // mode=ro
  67. private bool // cache=private: 不进共享注册表, 独立引擎实例
  68. }
  69. // parseDSN 解析 "文件路径?mode=ro&cache=private" 形式的 DSN。
  70. func parseDSN(dsn string) (*dsnConfig, error) {
  71. cfg := &dsnConfig{path: dsn}
  72. query := ""
  73. if i := strings.IndexByte(dsn, '?'); i >= 0 {
  74. cfg.path = dsn[:i]
  75. query = dsn[i+1:]
  76. }
  77. if cfg.path == "" {
  78. return nil, errors.New("vrtx: DSN 为空 (应为数据库文件路径)")
  79. }
  80. values, err := url.ParseQuery(query)
  81. if err != nil {
  82. return nil, fmt.Errorf("vrtx: DSN 参数解析失败: %w", err)
  83. }
  84. switch strings.ToLower(values.Get("mode")) {
  85. case "", "rw", "readwrite":
  86. case "ro", "readonly":
  87. cfg.readOnly = true
  88. default:
  89. return nil, fmt.Errorf("vrtx: 不支持的 mode=%q (应为 ro 或 rw)", values.Get("mode"))
  90. }
  91. if strings.EqualFold(values.Get("cache"), "private") {
  92. cfg.private = true
  93. }
  94. return cfg, nil
  95. }
  96. // openEngine 按 DSN 选项打开引擎。
  97. func openEngine(cfg *dsnConfig) (*core.DB, error) {
  98. if cfg.readOnly {
  99. return core.OpenWithOptions(cfg.path, core.OpenOptions{ReadOnly: true})
  100. }
  101. return core.Open(cfg.path)
  102. }
  103. func sharedFor(dsn string) (*shared, error) {
  104. cfg, err := parseDSN(dsn)
  105. if err != nil {
  106. return nil, err
  107. }
  108. // cache=private: 每次独立引擎实例, 不进共享注册表 (release 时直接 Close)。
  109. if cfg.private {
  110. db, err := openEngine(cfg)
  111. if err != nil {
  112. return nil, err
  113. }
  114. return &shared{db: db, dsn: dsn, refs: 1, sem: make(chan struct{}, 16)}, nil
  115. }
  116. registry.Lock()
  117. defer registry.Unlock()
  118. if s, ok := registry.m[dsn]; ok {
  119. s.refs++
  120. return s, nil
  121. }
  122. db, err := openEngine(cfg)
  123. if err != nil {
  124. return nil, err
  125. }
  126. s := &shared{db: db, dsn: dsn, refs: 1, sem: make(chan struct{}, 16)}
  127. registry.m[dsn] = s
  128. return s, nil
  129. }
  130. func (s *shared) release() error {
  131. registry.Lock()
  132. defer registry.Unlock()
  133. s.refs--
  134. if s.refs > 0 {
  135. return nil
  136. }
  137. delete(registry.m, s.dsn)
  138. return s.db.Close()
  139. }
  140. func (d *vrtxDriver) Open(dsn string) (driver.Conn, error) {
  141. if dsn == "" {
  142. return nil, errors.New("vrtx: DSN 为空 (应为数据库文件路径)")
  143. }
  144. s, err := sharedFor(dsn)
  145. if err != nil {
  146. return nil, fmt.Errorf("vrtx: 打开 %s: %w", dsn, err)
  147. }
  148. return &conn{s: s}, nil
  149. }
  150. // OpenConnector 实现 driver.DriverContext: database/sql 打开时优先走 Connector
  151. // (支持 sql.OpenDB、可固定 DSN); 此处提前校验 DSN, 参数错误在 Open 阶段就暴露。
  152. func (d *vrtxDriver) OpenConnector(dsn string) (driver.Connector, error) {
  153. if dsn == "" {
  154. return nil, errors.New("vrtx: DSN 为空 (应为数据库文件路径)")
  155. }
  156. if _, err := parseDSN(dsn); err != nil {
  157. return nil, err
  158. }
  159. return &vrtxConnector{drv: d, dsn: dsn}, nil
  160. }
  161. // vrtxConnector 实现 driver.Connector。
  162. type vrtxConnector struct {
  163. drv *vrtxDriver
  164. dsn string
  165. }
  166. // Connect 打开一个连接; 引擎打开/WAL 恢复不可中断, 但在已取消 ctx 下快速失败。
  167. func (c *vrtxConnector) Connect(ctx context.Context) (driver.Conn, error) {
  168. if err := ctx.Err(); err != nil {
  169. return nil, err
  170. }
  171. s, err := sharedFor(c.dsn)
  172. if err != nil {
  173. return nil, fmt.Errorf("vrtx: 打开 %s: %w", c.dsn, err)
  174. }
  175. return &conn{s: s}, nil
  176. }
  177. func (c *vrtxConnector) Driver() driver.Driver { return c.drv }
  178. var _ driver.DriverContext = (*vrtxDriver)(nil)
  179. // conn 实现 driver.Conn / driver.ConnBeginTx / driver.ExecerContext /
  180. // driver.QueryerContext / driver.Pinger / driver.NamedValueChecker。
  181. type conn struct {
  182. s *shared
  183. // activeTx 本连接上开着的事务: 事务期间持有串行锁, 拥有者连接上的
  184. // Exec/Query 不得重复加锁 (否则自死锁); 其它连接的操作照常抢锁,
  185. // 在事务提交/回滚前一律阻塞 —— 这就是全局串行化的实现方式。
  186. activeTx *core.Transaction
  187. }
  188. var (
  189. _ driver.Conn = (*conn)(nil)
  190. _ driver.ConnBeginTx = (*conn)(nil)
  191. _ driver.ExecerContext = (*conn)(nil)
  192. _ driver.QueryerContext = (*conn)(nil)
  193. _ driver.Pinger = (*conn)(nil)
  194. _ driver.NamedValueChecker = (*conn)(nil)
  195. )
  196. func (c *conn) Prepare(query string) (driver.Stmt, error) {
  197. st, err := parse(query)
  198. if err != nil {
  199. return nil, err
  200. }
  201. return &stmt{c: c, st: st}, nil
  202. }
  203. func (c *conn) Close() error {
  204. if c.s == nil {
  205. return nil
  206. }
  207. if c.activeTx != nil {
  208. // 防御: 连接带着未决事务被回收 —— 回滚并放锁 (正常流程不会发生,
  209. // database/sql 在事务结束前不会回收连接)
  210. _ = c.activeTx.Rollback()
  211. c.activeTx = nil
  212. c.s.unlock()
  213. }
  214. s := c.s
  215. c.s = nil
  216. return s.release()
  217. }
  218. func (c *conn) Begin() (driver.Tx, error) {
  219. return c.BeginTx(context.Background(), driver.TxOptions{})
  220. }
  221. func (c *conn) BeginTx(ctx context.Context, _ driver.TxOptions) (driver.Tx, error) {
  222. if err := c.s.lock(ctx); err != nil {
  223. return nil, err
  224. }
  225. if c.s.db.HasActiveTransaction() {
  226. c.s.unlock()
  227. return nil, errors.New("vrtx: 已有活跃事务 (单写者模型禁止并发事务)")
  228. }
  229. c.activeTx = c.s.db.BeginTransaction()
  230. return &tx{txn: c.activeTx, s: c.s, c: c}, nil
  231. }
  232. func (c *conn) Ping(_ context.Context) error {
  233. // 引擎无活性探针: 句柄在 = 可服务 (打开时的 CRC/WAL 恢复已完成)。
  234. return nil
  235. }
  236. // CheckNamedValue 实现 driver.NamedValueChecker: 经默认转换器把基础参数规整为
  237. // driver 基础类型 (int→int64、float32→float64 等; time.Time/[]byte 原样保留),
  238. // 并明确拒绝命名参数 (解析器只认 ? 占位符)。
  239. func (c *conn) CheckNamedValue(nv *driver.NamedValue) error {
  240. if nv.Name != "" {
  241. return fmt.Errorf("vrtx: 不支持命名参数 %q, 请使用 ? 占位符", nv.Name)
  242. }
  243. v, err := driver.DefaultParameterConverter.ConvertValue(nv.Value)
  244. if err != nil {
  245. return err
  246. }
  247. nv.Value = v
  248. return nil
  249. }
  250. func (c *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
  251. st, err := parse(query)
  252. if err != nil {
  253. return nil, err
  254. }
  255. if st.kind == kSelect || st.kind == kShow {
  256. return nil, errors.New("vrtx: 查询语句 (SELECT/SHOW) 请使用 QueryContext / Query")
  257. }
  258. if c.activeTx == nil {
  259. if err := c.s.lock(ctx); err != nil {
  260. return nil, err
  261. }
  262. defer c.s.unlock()
  263. }
  264. res, err := execStatement(c.s.db, st, args)
  265. return res, classifyError(err)
  266. }
  267. func (c *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
  268. st, err := parse(query)
  269. if err != nil {
  270. return nil, err
  271. }
  272. if st.kind != kSelect && st.kind != kShow {
  273. return nil, errors.New("vrtx: 非查询语句请使用 ExecContext / Exec")
  274. }
  275. var release func()
  276. if c.activeTx == nil {
  277. if err := c.s.lock(ctx); err != nil {
  278. return nil, err
  279. }
  280. release = c.s.unlock
  281. }
  282. if st.kind == kShow {
  283. rr, e := execShow(c.s.db, st.show, release)
  284. return rr, classifyError(e)
  285. }
  286. rr, e := queryStatement(ctx, c.s.db, st.sel, args, release)
  287. return rr, classifyError(e)
  288. }
  289. // tx 实现 driver.Tx。Commit/Rollback 释放串行锁 (Begin 时持有)。
  290. type tx struct {
  291. txn *core.Transaction
  292. s *shared
  293. c *conn
  294. }
  295. func (t *tx) Commit() error {
  296. err := t.txn.Commit()
  297. t.c.activeTx = nil
  298. t.s.unlock()
  299. return err
  300. }
  301. func (t *tx) Rollback() error {
  302. err := t.txn.Rollback()
  303. t.c.activeTx = nil
  304. t.s.unlock()
  305. return err
  306. }
  307. // stmt 实现 driver.Stmt (Prepare 路径: 解析已完成, 执行时只绑定参数)。
  308. type stmt struct {
  309. c *conn
  310. st *statement
  311. }
  312. var (
  313. _ driver.Stmt = (*stmt)(nil)
  314. _ driver.StmtExecContext = (*stmt)(nil)
  315. _ driver.StmtQueryContext = (*stmt)(nil)
  316. _ driver.NamedValueChecker = (*stmt)(nil)
  317. )
  318. func (s *stmt) Close() error { return nil }
  319. func (s *stmt) NumInput() int { return s.st.argCount() }
  320. func (s *stmt) Exec(args []driver.Value) (driver.Result, error) {
  321. return s.execContext(context.Background(), valuesToNamed(args))
  322. }
  323. func (s *stmt) Query(args []driver.Value) (driver.Rows, error) {
  324. return s.queryContext(context.Background(), valuesToNamed(args))
  325. }
  326. // ExecContext 实现 driver.StmtExecContext。
  327. func (s *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
  328. return s.execContext(ctx, args)
  329. }
  330. // QueryContext 实现 driver.StmtQueryContext。
  331. func (s *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
  332. return s.queryContext(ctx, args)
  333. }
  334. func (s *stmt) CheckNamedValue(nv *driver.NamedValue) error {
  335. return s.c.CheckNamedValue(nv)
  336. }
  337. func (s *stmt) execContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
  338. if s.st.kind == kSelect || s.st.kind == kShow {
  339. return nil, errors.New("vrtx: 查询语句请使用 Query")
  340. }
  341. if s.c.activeTx == nil {
  342. if err := s.c.s.lock(ctx); err != nil {
  343. return nil, err
  344. }
  345. defer s.c.s.unlock()
  346. }
  347. res, err := execStatement(s.c.s.db, s.st, args)
  348. return res, classifyError(err)
  349. }
  350. func (s *stmt) queryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
  351. if s.st.kind != kSelect && s.st.kind != kShow {
  352. return nil, errors.New("vrtx: 非查询语句请使用 Exec")
  353. }
  354. var release func()
  355. if s.c.activeTx == nil {
  356. if err := s.c.s.lock(ctx); err != nil {
  357. return nil, err
  358. }
  359. release = s.c.s.unlock
  360. }
  361. if s.st.kind == kShow {
  362. rr, e := execShow(s.c.s.db, s.st.show, release)
  363. return rr, classifyError(e)
  364. }
  365. rr, e := queryStatement(ctx, s.c.s.db, s.st.sel, args, release)
  366. return rr, classifyError(e)
  367. }
  368. func valuesToNamed(args []driver.Value) []driver.NamedValue {
  369. out := make([]driver.NamedValue, len(args))
  370. for i, v := range args {
  371. out[i] = driver.NamedValue{Ordinal: i + 1, Value: v}
  372. }
  373. return out
  374. }
  375. // streamBuf 流式结果集 channel 缓冲行数。
  376. const streamBuf = 64
  377. // rows 同时支持两种模式:
  378. // - 流式 (ch != nil): 普通 SELECT, worker 逐行回调送入; Close 前持锁。
  379. // - 物化 (ch == nil): 单行聚合 / JOIN / SHOW, 执行已完成、锁已释放。
  380. //
  381. // blobReader 物化 Blob 列的读取入口 (blobReaderOf 绑定具体表): Blob 列行内只有
  382. // 8B 链引用, 结果集要的是内容字节 —— 流式路径在 worker 里 (持锁期间) 解引用。
  383. // 物化模式的两条路径不经过它: JOIN 在 scanJoinTable 里当场解引用 (join.go),
  384. // 聚合/SHOW/字面量行根本不产出 BlobRef。
  385. type rows struct {
  386. cols []string
  387. metas []colMeta
  388. // 流式
  389. ch chan []driver.Value
  390. done chan struct{}
  391. ended chan struct{}
  392. once sync.Once
  393. err error
  394. // 物化
  395. data [][]driver.Value
  396. pos int
  397. blobReader func(types.BlobRef) ([]byte, error)
  398. release func()
  399. }
  400. var (
  401. _ driver.Rows = (*rows)(nil)
  402. _ driver.RowsColumnTypeDatabaseTypeName = (*rows)(nil)
  403. _ driver.RowsColumnTypeNullable = (*rows)(nil)
  404. _ driver.RowsColumnTypeScanType = (*rows)(nil)
  405. _ driver.RowsColumnTypeLength = (*rows)(nil)
  406. )
  407. func newStreamRows(cols []string, metas []colMeta, blobReader func(types.BlobRef) ([]byte, error), release func()) *rows {
  408. return &rows{
  409. cols: cols,
  410. metas: metas,
  411. ch: make(chan []driver.Value, streamBuf),
  412. done: make(chan struct{}),
  413. ended: make(chan struct{}),
  414. blobReader: blobReader,
  415. release: release,
  416. }
  417. }
  418. func materialRows(cols []string, metas []colMeta, data [][]driver.Value) *rows {
  419. return &rows{cols: cols, metas: metas, data: data}
  420. }
  421. // start 启动 worker: 在已持锁状态下逐行扫描, 按 colNames 投影后送入 ch。
  422. // q.Scan 的回调给的是未投影完整行, 故这里按 FieldName 自行挑列。
  423. func (r *rows) start(ctx context.Context, colNames []string, distinct bool, q *core.Query) {
  424. go func() {
  425. defer close(r.ended)
  426. defer close(r.ch)
  427. var seen map[string]bool
  428. if distinct {
  429. seen = make(map[string]bool)
  430. }
  431. scanErr := q.Scan(func(full []types.FieldValue) bool {
  432. // 列名→下标映射【每行重建】: 引擎的行是稀疏编码 (NULL 列物理缺席),
  433. // 每行字段数不同、同一下标在不同行对应不同列 — 按第一行建表复用会让
  434. // 第二行起映射错位, 行更短直接索引越界 panic (迁移数据必读崩)。
  435. pos := make(map[string]int, len(full))
  436. for i, fv := range full {
  437. pos[strings.ToLower(string(fv.FieldName))] = i
  438. }
  439. vals := make([]driver.Value, len(colNames))
  440. for i, cn := range colNames {
  441. idx, ok := pos[strings.ToLower(cn)]
  442. if !ok {
  443. // 旧版本行不含后加的列 (schema 演进): 新列对旧行 = NULL。
  444. vals[i] = nil
  445. continue
  446. }
  447. raw := full[idx].Value
  448. if ref, isRef := raw.(types.BlobRef); isRef && r.blobReader != nil {
  449. // Blob 列行内只有 8B 链引用: 在持锁的 worker 里解引用成内容字节。
  450. data, err := r.blobReader(ref)
  451. if err != nil {
  452. r.err = fmt.Errorf("读取 BLOB 列 %q: %w", cn, err)
  453. return false
  454. }
  455. vals[i] = data
  456. continue
  457. }
  458. dv, err := fieldValueToDriverTyped(r.metas[i].ft, raw)
  459. if err != nil {
  460. r.err = err
  461. return false
  462. }
  463. vals[i] = dv
  464. }
  465. if seen != nil {
  466. key := distinctKey(vals)
  467. if seen[key] {
  468. return true // 重复组合: 跳过本行, 继续扫描
  469. }
  470. seen[key] = true
  471. }
  472. select {
  473. case r.ch <- vals:
  474. return true
  475. case <-r.done:
  476. return false
  477. case <-ctx.Done():
  478. r.err = ctx.Err()
  479. return false
  480. }
  481. })
  482. if scanErr != nil && r.err == nil {
  483. r.err = scanErr
  484. }
  485. }()
  486. }
  487. // distinctKey 把投影后的一行 driver.Value 编成无歧义字符串 (类型标记 + 长度前缀),
  488. // 作为 SELECT DISTINCT 的去重键。
  489. func distinctKey(vals []driver.Value) string {
  490. var sb strings.Builder
  491. for _, v := range vals {
  492. switch x := v.(type) {
  493. case nil:
  494. sb.WriteString("N:0:")
  495. case string:
  496. sb.WriteString("S:")
  497. sb.WriteString(strconv.Itoa(len(x)))
  498. sb.WriteByte(':')
  499. sb.WriteString(x)
  500. case []byte:
  501. sb.WriteString("B:")
  502. sb.WriteString(strconv.Itoa(len(x)))
  503. sb.WriteByte(':')
  504. sb.Write(x)
  505. case time.Time:
  506. sb.WriteString("T:")
  507. sb.WriteString(strconv.FormatInt(x.UnixNano(), 10))
  508. sb.WriteByte(':')
  509. case bool:
  510. sb.WriteString("L:")
  511. if x {
  512. sb.WriteByte('1')
  513. } else {
  514. sb.WriteByte('0')
  515. }
  516. sb.WriteByte(':')
  517. case int64:
  518. sb.WriteString("I:")
  519. sb.WriteString(strconv.FormatInt(x, 10))
  520. sb.WriteByte(':')
  521. case float64:
  522. sb.WriteString("F:")
  523. sb.WriteString(strconv.FormatFloat(x, 'g', -1, 64))
  524. sb.WriteByte(':')
  525. default:
  526. sb.WriteString("?:")
  527. sb.WriteString(fmt.Sprintf("%T:%v", x, x))
  528. }
  529. }
  530. return sb.String()
  531. }
  532. func (r *rows) Columns() []string { return r.cols }
  533. func (r *rows) Close() error {
  534. r.once.Do(func() {
  535. if r.done != nil {
  536. close(r.done)
  537. }
  538. if r.ended != nil {
  539. <-r.ended // 等 worker 完全退出、不再访问引擎, 然后才放锁
  540. }
  541. if r.release != nil {
  542. r.release()
  543. r.release = nil
  544. }
  545. })
  546. return nil
  547. }
  548. func (r *rows) Next(dest []driver.Value) error {
  549. if r.ch != nil {
  550. row, ok := <-r.ch
  551. if !ok {
  552. <-r.ended
  553. if r.err != nil {
  554. return classifyError(r.err)
  555. }
  556. return io.EOF
  557. }
  558. copy(dest, row)
  559. return nil
  560. }
  561. if r.pos >= len(r.data) {
  562. return io.EOF
  563. }
  564. copy(dest, r.data[r.pos])
  565. r.pos++
  566. return nil
  567. }
  568. // ColumnType* 系列: 供 sqlx/GORM 等做列类型反射。
  569. func (r *rows) ColumnTypeDatabaseTypeName(i int) string {
  570. if i >= 0 && i < len(r.metas) {
  571. return r.metas[i].dbName
  572. }
  573. return ""
  574. }
  575. func (r *rows) ColumnTypeNullable(i int) (bool, bool) {
  576. if i >= 0 && i < len(r.metas) {
  577. return r.metas[i].nullable, true
  578. }
  579. return true, false
  580. }
  581. func (r *rows) ColumnTypeScanType(i int) reflect.Type {
  582. if i >= 0 && i < len(r.metas) {
  583. return r.metas[i].scanType
  584. }
  585. return reflect.TypeOf("")
  586. }
  587. func (r *rows) ColumnTypeLength(i int) (int64, bool) {
  588. if i >= 0 && i < len(r.metas) && r.metas[i].hasLen {
  589. return r.metas[i].length, true
  590. }
  591. return 0, false
  592. }
  593. // result 实现 driver.Result。
  594. type result struct {
  595. lastID int64
  596. affected int64
  597. }
  598. func (r *result) LastInsertId() (int64, error) { return r.lastID, nil }
  599. func (r *result) RowsAffected() (int64, error) { return r.affected, nil }