//go:build kvdb_sqlite && !(windows && (arm || 386)) && !(linux && (ppc64 || mips || mipsle || mips64)) package sqlite import ( "context" "fmt" "net/url" "path/filepath" "github.com/btcsuite/btcwallet/walletdb" "github.com/lightningnetwork/lnd/kvdb/sqlbase" _ "modernc.org/sqlite" // Register relevant drivers. ) const ( // sqliteOptionPrefix is the string prefix sqlite uses to set various // options. This is used in the following format: // * sqliteOptionPrefix || option_name = option_value. sqliteOptionPrefix = "_pragma" // sqliteTxLockImmediate is a dsn option used to ensure that write // transactions are started immediately. sqliteTxLockImmediate = "_txlock=immediate" ) // NewSqliteBackend returns a db object initialized with the passed backend // config. If a sqlite connection cannot be established, then an error is // returned. func NewSqliteBackend(ctx context.Context, cfg *Config, dbPath, fileName, prefix string) (walletdb.DB, error) { // First, we add a set of mandatory pragma options to the query. pragmaOptions := []struct { name string value string }{ { name: "busy_timeout", value: fmt.Sprintf( "%d", cfg.BusyTimeout.Milliseconds(), ), }, { name: "foreign_keys", value: "on", }, { name: "journal_mode", value: "WAL", }, } sqliteOptions := make(url.Values) for _, option := range pragmaOptions { sqliteOptions.Add( sqliteOptionPrefix, fmt.Sprintf("%v=%v", option.name, option.value), ) } // Then we add any user specified pragma options. Note that these can // be of the form: "key=value", "key(N)" or "key". for _, option := range cfg.PragmaOptions { sqliteOptions.Add(sqliteOptionPrefix, option) } // Construct the DSN which is just the database file name, appended // with the series of pragma options as a query URL string. For more // details on the formatting here, see the modernc.org/sqlite docs: // https://pkg.go.dev/modernc.org/sqlite#Driver.Open. dsn := fmt.Sprintf( "%v?%v&%v", filepath.Join(dbPath, fileName), sqliteOptions.Encode(), sqliteTxLockImmediate, ) sqlCfg := &sqlbase.Config{ DriverName: "sqlite", Dsn: dsn, Timeout: cfg.Timeout, TableNamePrefix: prefix, } return sqlbase.NewSqlBackend(ctx, sqlCfg) }