sqlite.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package sqlite
  2. import (
  3. "context"
  4. "database/sql"
  5. "strconv"
  6. "gorm.io/gorm/callbacks"
  7. _ "github.com/mattn/go-sqlite3"
  8. "gorm.io/gorm"
  9. "gorm.io/gorm/clause"
  10. "gorm.io/gorm/logger"
  11. "gorm.io/gorm/migrator"
  12. "gorm.io/gorm/schema"
  13. )
  14. // DriverName is the default driver name for SQLite.
  15. const DriverName = "sqlite3"
  16. type Dialector struct {
  17. DriverName string
  18. DSN string
  19. Conn gorm.ConnPool
  20. }
  21. type Config struct {
  22. DriverName string
  23. DSN string
  24. Conn gorm.ConnPool
  25. }
  26. func Open(dsn string) gorm.Dialector {
  27. return &Dialector{DSN: dsn}
  28. }
  29. func New(config Config) gorm.Dialector {
  30. return &Dialector{DSN: config.DSN, DriverName: config.DriverName, Conn: config.Conn}
  31. }
  32. func (dialector Dialector) Name() string {
  33. return "sqlite"
  34. }
  35. func (dialector Dialector) Initialize(db *gorm.DB) (err error) {
  36. if dialector.DriverName == "" {
  37. dialector.DriverName = DriverName
  38. }
  39. if dialector.Conn != nil {
  40. db.ConnPool = dialector.Conn
  41. } else {
  42. conn, err := sql.Open(dialector.DriverName, dialector.DSN)
  43. if err != nil {
  44. return err
  45. }
  46. db.ConnPool = conn
  47. }
  48. var version string
  49. if err := db.ConnPool.QueryRowContext(context.Background(), "select sqlite_version()").Scan(&version); err != nil {
  50. return err
  51. }
  52. // https://www.sqlite.org/releaselog/3_35_0.html
  53. if compareVersion(version, "3.35.0") >= 0 {
  54. callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{
  55. CreateClauses: []string{"INSERT", "VALUES", "ON CONFLICT", "RETURNING"},
  56. UpdateClauses: []string{"UPDATE", "SET", "FROM", "WHERE", "RETURNING"},
  57. DeleteClauses: []string{"DELETE", "FROM", "WHERE", "RETURNING"},
  58. LastInsertIDReversed: true,
  59. })
  60. } else {
  61. callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{
  62. LastInsertIDReversed: true,
  63. })
  64. }
  65. for k, v := range dialector.ClauseBuilders() {
  66. db.ClauseBuilders[k] = v
  67. }
  68. return
  69. }
  70. func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder {
  71. return map[string]clause.ClauseBuilder{
  72. "INSERT": func(c clause.Clause, builder clause.Builder) {
  73. if insert, ok := c.Expression.(clause.Insert); ok {
  74. if stmt, ok := builder.(*gorm.Statement); ok {
  75. stmt.WriteString("INSERT ")
  76. if insert.Modifier != "" {
  77. stmt.WriteString(insert.Modifier)
  78. stmt.WriteByte(' ')
  79. }
  80. stmt.WriteString("INTO ")
  81. if insert.Table.Name == "" {
  82. stmt.WriteQuoted(stmt.Table)
  83. } else {
  84. stmt.WriteQuoted(insert.Table)
  85. }
  86. return
  87. }
  88. }
  89. c.Build(builder)
  90. },
  91. "LIMIT": func(c clause.Clause, builder clause.Builder) {
  92. if limit, ok := c.Expression.(clause.Limit); ok {
  93. var lmt = -1
  94. if limit.Limit != nil && *limit.Limit >= 0 {
  95. lmt = *limit.Limit
  96. }
  97. if lmt >= 0 || limit.Offset > 0 {
  98. builder.WriteString("LIMIT ")
  99. builder.WriteString(strconv.Itoa(lmt))
  100. }
  101. if limit.Offset > 0 {
  102. builder.WriteString(" OFFSET ")
  103. builder.WriteString(strconv.Itoa(limit.Offset))
  104. }
  105. }
  106. },
  107. "FOR": func(c clause.Clause, builder clause.Builder) {
  108. if _, ok := c.Expression.(clause.Locking); ok {
  109. // SQLite3 does not support row-level locking.
  110. return
  111. }
  112. c.Build(builder)
  113. },
  114. }
  115. }
  116. func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression {
  117. if field.AutoIncrement {
  118. return clause.Expr{SQL: "NULL"}
  119. }
  120. // doesn't work, will raise error
  121. return clause.Expr{SQL: "DEFAULT"}
  122. }
  123. func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator {
  124. return Migrator{migrator.Migrator{Config: migrator.Config{
  125. DB: db,
  126. Dialector: dialector,
  127. CreateIndexAfterCreateTable: true,
  128. }}}
  129. }
  130. func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) {
  131. writer.WriteByte('?')
  132. }
  133. func (dialector Dialector) QuoteTo(writer clause.Writer, str string) {
  134. var (
  135. underQuoted, selfQuoted bool
  136. continuousBacktick int8
  137. shiftDelimiter int8
  138. )
  139. for _, v := range []byte(str) {
  140. switch v {
  141. case '`':
  142. continuousBacktick++
  143. if continuousBacktick == 2 {
  144. writer.WriteString("``")
  145. continuousBacktick = 0
  146. }
  147. case '.':
  148. if continuousBacktick > 0 || !selfQuoted {
  149. shiftDelimiter = 0
  150. underQuoted = false
  151. continuousBacktick = 0
  152. writer.WriteString("`")
  153. }
  154. writer.WriteByte(v)
  155. continue
  156. default:
  157. if shiftDelimiter-continuousBacktick <= 0 && !underQuoted {
  158. writer.WriteString("`")
  159. underQuoted = true
  160. if selfQuoted = continuousBacktick > 0; selfQuoted {
  161. continuousBacktick -= 1
  162. }
  163. }
  164. for ; continuousBacktick > 0; continuousBacktick -= 1 {
  165. writer.WriteString("``")
  166. }
  167. writer.WriteByte(v)
  168. }
  169. shiftDelimiter++
  170. }
  171. if continuousBacktick > 0 && !selfQuoted {
  172. writer.WriteString("``")
  173. }
  174. writer.WriteString("`")
  175. }
  176. func (dialector Dialector) Explain(sql string, vars ...interface{}) string {
  177. return logger.ExplainSQL(sql, nil, `"`, vars...)
  178. }
  179. func (dialector Dialector) DataTypeOf(field *schema.Field) string {
  180. switch field.DataType {
  181. case schema.Bool:
  182. return "numeric"
  183. case schema.Int, schema.Uint:
  184. if field.AutoIncrement {
  185. // doesn't check `PrimaryKey`, to keep backward compatibility
  186. // https://www.sqlite.org/autoinc.html
  187. return "integer PRIMARY KEY AUTOINCREMENT"
  188. } else {
  189. return "integer"
  190. }
  191. case schema.Float:
  192. return "real"
  193. case schema.String:
  194. return "text"
  195. case schema.Time:
  196. // Distinguish between schema.Time and tag time
  197. if val, ok := field.TagSettings["TYPE"]; ok {
  198. return val
  199. } else {
  200. return "datetime"
  201. }
  202. case schema.Bytes:
  203. return "blob"
  204. }
  205. return string(field.DataType)
  206. }
  207. func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error {
  208. tx.Exec("SAVEPOINT " + name)
  209. return nil
  210. }
  211. func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error {
  212. tx.Exec("ROLLBACK TO SAVEPOINT " + name)
  213. return nil
  214. }
  215. func compareVersion(version1, version2 string) int {
  216. n, m := len(version1), len(version2)
  217. i, j := 0, 0
  218. for i < n || j < m {
  219. x := 0
  220. for ; i < n && version1[i] != '.'; i++ {
  221. x = x*10 + int(version1[i]-'0')
  222. }
  223. i++
  224. y := 0
  225. for ; j < m && version2[j] != '.'; j++ {
  226. y = y*10 + int(version2[j]-'0')
  227. }
  228. j++
  229. if x > y {
  230. return 1
  231. }
  232. if x < y {
  233. return -1
  234. }
  235. }
  236. return 0
  237. }