db_schema.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. // Copyright (C) 2025 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package sqlite
  7. import (
  8. "embed"
  9. "io/fs"
  10. "strings"
  11. "time"
  12. "github.com/syncthing/syncthing/lib/build"
  13. )
  14. const currentSchemaVersion = 1
  15. //go:embed sql/**
  16. var embedded embed.FS
  17. func (s *DB) runScripts(glob string, filter ...func(s string) bool) error {
  18. scripts, err := fs.Glob(embedded, glob)
  19. if err != nil {
  20. return wrap(err)
  21. }
  22. tx, err := s.sql.Begin()
  23. if err != nil {
  24. return wrap(err)
  25. }
  26. defer tx.Rollback() //nolint:errcheck
  27. nextScript:
  28. for _, scr := range scripts {
  29. for _, fn := range filter {
  30. if !fn(scr) {
  31. l.Debugln("Skipping script", scr)
  32. continue nextScript
  33. }
  34. }
  35. l.Debugln("Executing script", scr)
  36. bs, err := fs.ReadFile(embedded, scr)
  37. if err != nil {
  38. return wrap(err, scr)
  39. }
  40. // SQLite requires one statement per exec, so we split the init
  41. // files on lines containing only a semicolon and execute them
  42. // separately. We require it on a separate line because there are
  43. // also statement-internal semicolons in the triggers.
  44. for _, stmt := range strings.Split(string(bs), "\n;") {
  45. if _, err := tx.Exec(stmt); err != nil {
  46. return wrap(err, stmt)
  47. }
  48. }
  49. }
  50. return wrap(tx.Commit())
  51. }
  52. type schemaVersion struct {
  53. SchemaVersion int
  54. AppliedAt int64
  55. SyncthingVersion string
  56. }
  57. func (s *schemaVersion) AppliedTime() time.Time {
  58. return time.Unix(0, s.AppliedAt)
  59. }
  60. func (s *DB) setAppliedSchemaVersion(ver int) error {
  61. _, err := s.stmt(`
  62. INSERT OR IGNORE INTO schemamigrations (schema_version, applied_at, syncthing_version)
  63. VALUES (?, ?, ?)
  64. `).Exec(ver, time.Now().UnixNano(), build.LongVersion)
  65. return wrap(err)
  66. }
  67. func (s *DB) getAppliedSchemaVersion() (schemaVersion, error) {
  68. var v schemaVersion
  69. err := s.stmt(`
  70. SELECT schema_version as schemaversion, applied_at as appliedat, syncthing_version as syncthingversion FROM schemamigrations
  71. ORDER BY schema_version DESC
  72. LIMIT 1
  73. `).Get(&v)
  74. return v, wrap(err)
  75. }