driver.go 17 KB

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