(path string, maxConns int, pragmas, schemaScripts, migrationScripts []string)
| 50 | } |
| 51 | |
| 52 | func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScripts []string) (*baseDB, error) { |
| 53 | // Open the database with options to enable foreign keys and recursive |
| 54 | // triggers (needed for the delete+insert triggers on row replace). |
| 55 | pathURL := url.URL{ |
| 56 | Scheme: "file", |
| 57 | Path: fileToUriPath(path), |
| 58 | RawQuery: commonOptions, |
| 59 | } |
| 60 | sqlDB, err := sqlx.Open(dbDriver, pathURL.String()) |
| 61 | if err != nil { |
| 62 | return nil, wrap(err) |
| 63 | } |
| 64 | |
| 65 | sqlDB.SetMaxOpenConns(maxConns) |
| 66 | sqlDB.SetMaxIdleConns(maxConns) |
| 67 | |
| 68 | for _, pragma := range pragmas { |
| 69 | if _, err := sqlDB.Exec("PRAGMA " + pragma); err != nil { |
| 70 | return nil, wrap(err, "PRAGMA "+pragma) |
| 71 | } |
| 72 | } |
| 73 | |
| 74 | db := &baseDB{ |
| 75 | path: path, |
| 76 | baseName: filepath.Base(path), |
| 77 | sql: sqlDB, |
| 78 | statements: make(map[string]*sqlx.Stmt), |
| 79 | tplInput: map[string]any{ |
| 80 | "FlagLocalUnsupported": protocol.FlagLocalUnsupported, |
| 81 | "FlagLocalIgnored": protocol.FlagLocalIgnored, |
| 82 | "FlagLocalMustRescan": protocol.FlagLocalMustRescan, |
| 83 | "FlagLocalReceiveOnly": protocol.FlagLocalReceiveOnly, |
| 84 | "FlagLocalGlobal": protocol.FlagLocalGlobal, |
| 85 | "FlagLocalNeeded": protocol.FlagLocalNeeded, |
| 86 | "FlagLocalRemoteInvalid": protocol.FlagLocalRemoteInvalid, |
| 87 | "LocalInvalidFlags": protocol.LocalInvalidFlags, |
| 88 | "SyncthingVersion": build.LongVersion, |
| 89 | }, |
| 90 | } |
| 91 | |
| 92 | // Create a specific connection for the schema setup and migration to |
| 93 | // run in. We do this because we need to disable foreign keys for the |
| 94 | // duration, which is a thing that needs to happen outside of a |
| 95 | // transaction and affects the connection it's run on. So we need to a) |
| 96 | // make sure all our commands run on this specific connection (which the |
| 97 | // transaction accomplishes naturally) and b) make sure these pragmas |
| 98 | // don't leak to anyone else afterwards. |
| 99 | ctx := context.TODO() |
| 100 | conn, err := db.sql.Connx(ctx) |
| 101 | if err != nil { |
| 102 | return nil, wrap(err) |
| 103 | } |
| 104 | defer func() { |
| 105 | _, _ = conn.ExecContext(ctx, "PRAGMA foreign_keys = ON") |
| 106 | _, _ = conn.ExecContext(ctx, "PRAGMA legacy_alter_table = OFF") |
| 107 | conn.Close() |
| 108 | }() |
| 109 | if _, err := conn.ExecContext(ctx, "PRAGMA foreign_keys = OFF"); err != nil { |
no test coverage detected