Update Connection Options

* Rewrite order of options
* ADD: PRAGMA auto_vacuum
* ADD: Multi Boolean values
* UPD: README
* FIX: Case-Sensitive values
* Reduced code for:
  - foreign_keys
  - recursive_triggers
This commit is contained in:
Gert-Jan Timmer 2018-05-29 11:33:43 +02:00
parent a5cc8a2afa
commit efc41bcd27
2 changed files with 90 additions and 46 deletions

View File

@ -68,15 +68,20 @@ Options can be given using the following format: `KEYWORD=VALUE` and multiple op
This library supports dsn options of SQLite itself and provides additional options. This library supports dsn options of SQLite itself and provides additional options.
Boolean values can be one of:
* `0` `no` `false` `off`
* `1` `yes` `true` `on`
| Name | Key | Value(s) | Description | | Name | Key | Value(s) | Description |
|------|-----|----------|-------------| |------|-----|----------|-------------|
| Auto Vacuum | _vacuum | <ul><li>`0` \| `none`</li><li>`1` \| `full`</li><li>`2` \| `incremental`</li></ul> | For more information see [PRAGMA auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) |
| Busy Timeout | _busy_timeout | `int` | Specify value for sqlite3_busy_timeout. |
| Foreign Keys | _foreign_keys | `boolean` | Enable or disable enforcement of foreign keys. |
| Mutex Locking | _mutex | <ul><li>no</li><li>full</li></ul> | Specify mutex mode. |
| Recursive Triggers | _recursive_triggers | `boolean` | Enable or disable recursive triggers. |
| Shared-Cache Mode | cache | <ul><li>shared</li><li>private</li></ul> | Set cache mode for more information see [sqlite.org](https://www.sqlite.org/sharedcache.html) | | Shared-Cache Mode | cache | <ul><li>shared</li><li>private</li></ul> | Set cache mode for more information see [sqlite.org](https://www.sqlite.org/sharedcache.html) |
| Time Zone Location | _loc | auto | Specify location of time format. | | Time Zone Location | _loc | auto | Specify location of time format. |
| Busy Timeout | _busy_timeout | `int` | Specify value for sqlite3_busy_timeout. |
| Transaction Lock | _txlock | <ul><li>immediate</li><li>deferred</li><li>exclusive</li></ul> | Specify locking behavior for transactions. | | Transaction Lock | _txlock | <ul><li>immediate</li><li>deferred</li><li>exclusive</li></ul> | Specify locking behavior for transactions. |
| Foreign Keys | _foreign_keys | <ul><li>0</li><li>1</li></ul> | Enable or disable enforcement of foreign keys. |
| Recursive Triggers | _recursive_triggers | <ul><li>0</li><li>1</li></ul> | Enable or disable recursive triggers. |
| Mutex Locking | _mutex | <ul><li>no</li><li>full</li></ul> | Specify mutex mode. |
## DSN Examples ## DSN Examples

View File

@ -779,6 +779,14 @@ func errorString(err Error) string {
} }
// Open database and return a new connection. // Open database and return a new connection.
//
// A pragma can take either zero or one argument.
// The argument is may be either in parentheses or it may be separated from
// the pragma name by an equal sign. The two syntaxes yield identical results.
// In many pragmas, the argument is a boolean. The boolean can be one of:
// 1 yes true on
// 0 no false off
//
// You can specify a DSN string using a URI as the filename. // You can specify a DSN string using a URI as the filename.
// test.db // test.db
// file:test.db?cache=shared&mode=memory // file:test.db?cache=shared&mode=memory
@ -787,28 +795,43 @@ func errorString(err Error) string {
// go-sqlite3 adds the following query parameters to those used by SQLite: // go-sqlite3 adds the following query parameters to those used by SQLite:
// _loc=XXX // _loc=XXX
// Specify location of time format. It's possible to specify "auto". // Specify location of time format. It's possible to specify "auto".
// _busy_timeout=XXX //
// Specify value for sqlite3_busy_timeout. // _mutex=XXX
// Specify mutex mode. XXX can be "no", "full".
//
// _txlock=XXX // _txlock=XXX
// Specify locking behavior for transactions. XXX can be "immediate", // Specify locking behavior for transactions. XXX can be "immediate",
// "deferred", "exclusive". // "deferred", "exclusive".
//
// _busy_timeout=XXX
// Specify value for sqlite3_busy_timeout.
//
// _foreign_keys=X // _foreign_keys=X
// Enable or disable enforcement of foreign keys. X can be 1 or 0. // Enable or disable enforcement of foreign keys. X can be 1 or 0.
//
// _recursive_triggers=X // _recursive_triggers=X
// Enable or disable recursive triggers. X can be 1 or 0. // Enable or disable recursive triggers. X can be 1 or 0.
// _mutex=XXX //
// Specify mutex mode. XXX can be "no", "full". // _vacuum=X
// 0 | none - Auto Vacuum disabled
// 1 | full - Auto Vacuum FULL
// 2 | incremental - Auto Vacuum Incremental
func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) { func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
if C.sqlite3_threadsafe() == 0 { if C.sqlite3_threadsafe() == 0 {
return nil, errors.New("sqlite library was not compiled for thread-safe operation") return nil, errors.New("sqlite library was not compiled for thread-safe operation")
} }
// Options
var loc *time.Location var loc *time.Location
mutex := C.int(C.SQLITE_OPEN_FULLMUTEX)
txlock := "BEGIN" txlock := "BEGIN"
// PRAGMA's
autoVacuum := -1
busyTimeout := 5000 busyTimeout := 5000
foreignKeys := -1 foreignKeys := -1
recursiveTriggers := -1 recursiveTriggers := -1
mutex := C.int(C.SQLITE_OPEN_FULLMUTEX)
pos := strings.IndexRune(dsn, '?') pos := strings.IndexRune(dsn, '?')
if pos >= 1 { if pos >= 1 {
params, err := url.ParseQuery(dsn[pos+1:]) params, err := url.ParseQuery(dsn[pos+1:])
@ -828,13 +851,16 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
} }
} }
// _busy_timeout // _mutex
if val := params.Get("_busy_timeout"); val != "" { if val := params.Get("_mutex"); val != "" {
iv, err := strconv.ParseInt(val, 10, 64) switch val {
if err != nil { case "no":
return nil, fmt.Errorf("Invalid _busy_timeout: %v: %v", val, err) mutex = C.SQLITE_OPEN_NOMUTEX
case "full":
mutex = C.SQLITE_OPEN_FULLMUTEX
default:
return nil, fmt.Errorf("Invalid _mutex: %v", val)
} }
busyTimeout = int(iv)
} }
// _txlock // _txlock
@ -851,13 +877,36 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
} }
} }
// auto_vacuum
if val := params.Get("_vacuum"); val != "" {
switch strings.ToLower(val) {
case "0", "none":
autoVacuum = 0
case "1", "full":
autoVacuum = 1
case "2", "incremental":
autoVacuum = 2
default:
return nil, fmt.Errorf("Invalid _vacuum: %v", val)
}
}
// _busy_timeout
if val := params.Get("_busy_timeout"); val != "" {
iv, err := strconv.ParseInt(val, 10, 64)
if err != nil {
return nil, fmt.Errorf("Invalid _busy_timeout: %v: %v", val, err)
}
busyTimeout = int(iv)
}
// _foreign_keys // _foreign_keys
if val := params.Get("_foreign_keys"); val != "" { if val := params.Get("_foreign_keys"); val != "" {
switch val { switch strings.ToLower(val) {
case "1": case "0", "no", "false", "off":
foreignKeys = 1
case "0":
foreignKeys = 0 foreignKeys = 0
case "1", "yes", "true", "on":
foreignKeys = 1
default: default:
return nil, fmt.Errorf("Invalid _foreign_keys: %v", val) return nil, fmt.Errorf("Invalid _foreign_keys: %v", val)
} }
@ -865,28 +914,16 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
// _recursive_triggers // _recursive_triggers
if val := params.Get("_recursive_triggers"); val != "" { if val := params.Get("_recursive_triggers"); val != "" {
switch val { switch strings.ToLower(val) {
case "1": case "0", "no", "false", "off":
recursiveTriggers = 1
case "0":
recursiveTriggers = 0 recursiveTriggers = 0
case "1", "yes", "true", "on":
recursiveTriggers = 1
default: default:
return nil, fmt.Errorf("Invalid _recursive_triggers: %v", val) return nil, fmt.Errorf("Invalid _recursive_triggers: %v", val)
} }
} }
// _mutex
if val := params.Get("_mutex"); val != "" {
switch val {
case "no":
mutex = C.SQLITE_OPEN_NOMUTEX
case "full":
mutex = C.SQLITE_OPEN_FULLMUTEX
default:
return nil, fmt.Errorf("Invalid _mutex: %v", val)
}
}
if !strings.HasPrefix(dsn, "file:") { if !strings.HasPrefix(dsn, "file:") {
dsn = dsn[:pos] dsn = dsn[:pos]
} }
@ -920,24 +957,26 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
} }
return nil return nil
} }
if foreignKeys == 0 {
if err := exec("PRAGMA foreign_keys = OFF;"); err != nil { // Auto Vacuum
C.sqlite3_close_v2(db) if autoVacuum > -1 {
return nil, err if err := exec(fmt.Sprintf("PRAGMA auto_vacuum = %d;", autoVacuum)); err != nil {
}
} else if foreignKeys == 1 {
if err := exec("PRAGMA foreign_keys = ON;"); err != nil {
C.sqlite3_close_v2(db) C.sqlite3_close_v2(db)
return nil, err return nil, err
} }
} }
if recursiveTriggers == 0 {
if err := exec("PRAGMA recursive_triggers = OFF;"); err != nil { // Forgein Keys
if foreignKeys > -1 {
if err := exec(fmt.Sprintf("PRAGMA foreign_keys = %d;", foreignKeys)); err != nil {
C.sqlite3_close_v2(db) C.sqlite3_close_v2(db)
return nil, err return nil, err
} }
} else if recursiveTriggers == 1 { }
if err := exec("PRAGMA recursive_triggers = ON;"); err != nil {
// Recursive Triggers
if recursiveTriggers > -1 {
if err := exec(fmt.Sprintf("PRAGMA recursive_triggers = %d;", recursiveTriggers)); err != nil {
C.sqlite3_close_v2(db) C.sqlite3_close_v2(db)
return nil, err return nil, err
} }