fix: journal mode

Journal Mode should only be enforced when the user set it.

Fixes: #607
This commit is contained in:
Gert-Jan Timmer 2018-08-02 11:45:39 +02:00
parent 40492329dd
commit cf26002960
1 changed files with 133 additions and 120 deletions

View File

@ -334,7 +334,12 @@ func (j JournalMode) String() string {
}
const (
// JournalModeDelete is the normal behavior.
// JournalModeAuto is the journal mode in which the Journal is not explicitly set.
// This means that if any other program or connection already has set the journal mode
// the journal mode is automatically read from the database and not forcibly set.
JournalModeAuto = JournalMode("AUTO")
// JournalModeDelete is the normal behavior.
// In the DELETE mode, the rollback journal is deleted at the conclusion
// of each transaction.
// Indeed, the delete operation is the action that causes the transaction to commit.
@ -585,7 +590,7 @@ func NewConfig() *Config {
DeferForeignKeys: false,
ForeignKeyConstraints: false,
IgnoreCheckConstraints: false,
JournalMode: JournalModeDelete,
JournalMode: JournalModeAuto,
QueryOnly: false,
RecursiveTriggers: false,
SecureDelete: SecureDeleteOff,
@ -597,121 +602,6 @@ func NewConfig() *Config {
}
}
// FormatDSN formats the given Config into a DSN string which can be passed to
// the driver.
func (cfg *Config) FormatDSN() string {
var buf bytes.Buffer
params := url.Values{}
if len(cfg.Cache.String()) > 0 {
params.Set("cache", cfg.Cache.String())
}
if len(cfg.Mode.String()) > 0 {
params.Set("mode", cfg.Mode.String())
}
if len(cfg.Mutex.String()) > 0 {
params.Set("mutex", cfg.Mutex.String())
}
if cfg.Immutable {
params.Set("immutable", "true")
}
if cfg.TimeZone != nil {
if cfg.TimeZone == time.Local {
params.Set("tz", "auto")
} else {
params.Set("tz", cfg.TimeZone.String())
}
}
if cfg.BusyTimeout > 0 {
params.Set("timeout", cfg.BusyTimeout.String())
}
if len(cfg.TransactionLock.String()) > 0 && cfg.TransactionLock != TxLockDeferred {
params.Set("txlock", cfg.TransactionLock.String())
}
if len(cfg.LockingMode) > 0 && cfg.LockingMode != LockingModeNormal {
params.Set("lock", cfg.LockingMode.String())
}
if len(cfg.AutoVacuum) > 0 && cfg.AutoVacuum != AutoVacuumNone {
params.Set("vacuum", cfg.AutoVacuum.String())
}
if cfg.CaseSensitiveLike {
params.Set("cslike", "true")
}
if cfg.DeferForeignKeys {
params.Set("defer_fk", "true")
}
if cfg.ForeignKeyConstraints {
params.Set("fk", "true")
}
if cfg.IgnoreCheckConstraints {
params.Set("ignore_check_contraints", "true")
}
if len(cfg.JournalMode) > 0 && cfg.JournalMode != JournalModeDelete {
params.Set("journal", cfg.JournalMode.String())
}
if cfg.QueryOnly {
params.Set("query_only", "true")
}
if cfg.RecursiveTriggers {
params.Set("recursive_triggers", "true")
}
if len(cfg.SecureDelete) > 0 && cfg.SecureDelete != SecureDeleteOff {
params.Set("secure_delete", cfg.SecureDelete.String())
}
if len(cfg.Synchronous) > 0 && cfg.Synchronous != SynchronousNormal {
params.Set("sync", cfg.Synchronous.String())
}
if cfg.WriteableSchema {
params.Set("writable_schema", "true")
}
if cfg.Authentication != nil {
if len(cfg.Authentication.Username) > 0 && len(cfg.Authentication.Password) > 0 {
params.Set("user", cfg.Authentication.Username)
params.Set("pass", cfg.Authentication.Password)
if len(cfg.Authentication.Salt) > 0 {
params.Set("salt", cfg.Authentication.Salt)
}
if cfg.Authentication.Encoder != nil {
params.Set("crypt", cfg.Authentication.Encoder.String())
}
}
}
if !strings.HasPrefix(cfg.Database, "file:") {
buf.WriteString("file:")
}
buf.WriteString(cfg.Database)
// Append Options
if len(params) > 0 {
buf.WriteRune('?')
buf.WriteString(params.Encode())
}
return buf.String()
}
// Create connection from Configuration
func (cfg *Config) createConnection() (driver.Conn, error) {
if C.sqlite3_threadsafe() == 0 {
@ -933,9 +823,11 @@ func (cfg *Config) createConnection() (driver.Conn, error) {
}
// Journal Mode
if err := conn.PRAGMA(PRAGMA_JOURNAL_MODE, cfg.JournalMode.String()); err != nil {
C.sqlite3_close_v2(db)
return nil, err
if cfg.JournalMode != JournalModeAuto {
if err := conn.PRAGMA(PRAGMA_JOURNAL_MODE, cfg.JournalMode.String()); err != nil {
C.sqlite3_close_v2(db)
return nil, err
}
}
// Locking Mode
@ -1242,6 +1134,8 @@ func ParseDSN(dsn string) (cfg *Config, err error) {
// For WAL Mode set Synchronous Mode to 'NORMAL'
// See https://www.sqlite.org/pragma.html#pragma_synchronous
cfg.Synchronous = SynchronousNormal
case "AUTO":
cfg.JournalMode = JournalModeAuto
default:
return nil, fmt.Errorf("invalid journal: %v, expecting value of 'DELETE TRUNCATE PERSIST MEMORY WAL OFF'", val)
}
@ -1318,6 +1212,125 @@ func ParseDSN(dsn string) (cfg *Config, err error) {
return cfg, nil
}
// FormatDSN formats the given Config into a DSN string which can be passed to
// the driver.
func (cfg *Config) FormatDSN() string {
var buf bytes.Buffer
params := url.Values{}
if len(cfg.Key) > 0 {
params.Set("key", cfg.Key)
}
if len(cfg.Cache.String()) > 0 {
params.Set("cache", cfg.Cache.String())
}
if len(cfg.Mode.String()) > 0 {
params.Set("mode", cfg.Mode.String())
}
if len(cfg.Mutex.String()) > 0 {
params.Set("mutex", cfg.Mutex.String())
}
if cfg.Immutable {
params.Set("immutable", "true")
}
if cfg.TimeZone != nil {
if cfg.TimeZone == time.Local {
params.Set("tz", "auto")
} else {
params.Set("tz", cfg.TimeZone.String())
}
}
if cfg.BusyTimeout > 0 {
params.Set("timeout", cfg.BusyTimeout.String())
}
if len(cfg.TransactionLock.String()) > 0 && cfg.TransactionLock != TxLockDeferred {
params.Set("txlock", cfg.TransactionLock.String())
}
if len(cfg.LockingMode) > 0 && cfg.LockingMode != LockingModeNormal {
params.Set("lock", cfg.LockingMode.String())
}
if len(cfg.AutoVacuum) > 0 && cfg.AutoVacuum != AutoVacuumNone {
params.Set("vacuum", cfg.AutoVacuum.String())
}
if cfg.CaseSensitiveLike {
params.Set("cslike", "true")
}
if cfg.DeferForeignKeys {
params.Set("defer_fk", "true")
}
if cfg.ForeignKeyConstraints {
params.Set("fk", "true")
}
if cfg.IgnoreCheckConstraints {
params.Set("ignore_check_contraints", "true")
}
if len(cfg.JournalMode) > 0 && cfg.JournalMode != JournalModeDelete {
params.Set("journal", cfg.JournalMode.String())
}
if cfg.QueryOnly {
params.Set("query_only", "true")
}
if cfg.RecursiveTriggers {
params.Set("recursive_triggers", "true")
}
if len(cfg.SecureDelete) > 0 && cfg.SecureDelete != SecureDeleteOff {
params.Set("secure_delete", cfg.SecureDelete.String())
}
if len(cfg.Synchronous) > 0 && cfg.Synchronous != SynchronousNormal {
params.Set("sync", cfg.Synchronous.String())
}
if cfg.WriteableSchema {
params.Set("writable_schema", "true")
}
if cfg.Authentication != nil {
if len(cfg.Authentication.Username) > 0 && len(cfg.Authentication.Password) > 0 {
params.Set("user", cfg.Authentication.Username)
params.Set("pass", cfg.Authentication.Password)
if len(cfg.Authentication.Salt) > 0 {
params.Set("salt", cfg.Authentication.Salt)
}
if cfg.Authentication.Encoder != nil {
params.Set("crypt", cfg.Authentication.Encoder.String())
}
}
}
if !strings.HasPrefix(cfg.Database, "file:") {
buf.WriteString("file:")
}
buf.WriteString(cfg.Database)
// Append Options
if len(params) > 0 {
buf.WriteRune('?')
buf.WriteString(params.Encode())
}
return buf.String()
}
func normalizeParams(params url.Values) {
for k, v := range params {
params[strings.ToLower(k)] = v