commit
6f53a20d71
31
README.md
31
README.md
|
@ -68,15 +68,31 @@ 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.
|
||||
|
||||
Boolean values can be one of:
|
||||
* `0` `no` `false` `off`
|
||||
* `1` `yes` `true` `on`
|
||||
|
||||
| Name | Key | Value(s) | Description |
|
||||
|------|-----|----------|-------------|
|
||||
| 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. |
|
||||
| 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. |
|
||||
| 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. |
|
||||
| Auto Vacuum | `_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` \| `_timeout` | `int` | Specify value for sqlite3_busy_timeout. For more information see [PRAGMA busy_timeout](https://www.sqlite.org/pragma.html#pragma_busy_timeout) |
|
||||
| Case Sensitive LIKE | `_case_sensitive_like` \| `_cslike` | `boolean` | For more information see [PRAGMA case_sensitive_like](https://www.sqlite.org/pragma.html#pragma_case_sensitive_like) |
|
||||
| Defer Foreign Keys | `_defer_foreign_keys` \| `_defer_fk` | `boolean` | For more information see [PRAGMA defer_foreign_keys](https://www.sqlite.org/pragma.html#pragma_defer_foreign_keys) |
|
||||
| Foreign Keys | `_foreign_keys` \| `_fk` | `boolean` | For more information see [PRAGMA foreign_keys](https://www.sqlite.org/pragma.html#pragma_foreign_keys) |
|
||||
| Ignore CHECK Constraints | `_ignore_check_constraints` | `boolean` | For more information see [PRAGMA ignore_check_constraints](https://www.sqlite.org/pragma.html#pragma_ignore_check_constraints) |
|
||||
| Immutable | `immutable` | `boolean` | For more information see [Immutable](https://www.sqlite.org/c3ref/open.html) |
|
||||
| Journal Mode | `_journal_mode` \| `_journal` | <ul><li>DELETE</li><li>TRUNCATE</li><li>PERSIST</li><li>MEMORY</li><li>WAL</li><li>OFF</li></ul> | For more information see [PRAGMA journal_mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) |
|
||||
| Locking Mode | `_locking_mode` \| `_locking` | <ul><li>NORMAL</li><li>EXCLUSIVE</li></ul> | For more information see [PRAGMA locking_mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) |
|
||||
| Mode | `mode` | <ul><li>ro</li><li>rw</li><li>rwc</li><li>memory</li></ul> | Access Mode of the database. For more information see [SQLite Open](https://www.sqlite.org/c3ref/open.html) |
|
||||
| Mutex Locking | `_mutex` | <ul><li>no</li><li>full</li></ul> | Specify mutex mode. |
|
||||
| Query Only | `_query_only` | `boolean` | For more information see [PRAGMA query_only](https://www.sqlite.org/pragma.html#pragma_query_only) |
|
||||
| Recursive Triggers | `_recursive_triggers` \| `_rt` | `boolean` | For more information see [PRAGMA recursive_triggers](https://www.sqlite.org/pragma.html#pragma_recursive_triggers) |
|
||||
| Secure Delete | `_secure_delete` | `boolean` \| `FAST` | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) |
|
||||
| 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) |
|
||||
| Synchronous | `_synchronous` \| `_sync` | <ul><li>0 \| OFF</li><li>1 \| NORMAL</li><li>2 \| FULL</li><li>3 \| EXTRA</li></ul> | For more information see [PRAGMA synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) |
|
||||
| Time Zone Location | `_loc` | auto | Specify location of time format. |
|
||||
| Transaction Lock | `_txlock` | <ul><li>immediate</li><li>deferred</li><li>exclusive</li></ul> | Specify locking behavior for transactions. |
|
||||
| Writable Schema | `_writable_schema` | `Boolean` | When this pragma is on, the SQLITE_MASTER tables in which database can be changed using ordinary UPDATE, INSERT, and DELETE statements. Warning: misuse of this pragma can easily result in a corrupt database file. |
|
||||
|
||||
## DSN Examples
|
||||
|
||||
|
@ -124,6 +140,7 @@ go build --tags "icu json1 fts5 secure_delete"
|
|||
| Introspect PRAGMAS | sqlite_introspect | This option adds some extra PRAGMA statements. <ul><li>PRAGMA function_list</li><li>PRAGMA module_list</li><li>PRAGMA pragma_list</li></ul> |
|
||||
| JSON SQL Functions | sqlite_json | When this option is defined in the amalgamation, the JSON SQL functions are added to the build automatically |
|
||||
| Secure Delete | sqlite_secure_delete | This compile-time option changes the default setting of the secure_delete pragma.<br><br>When this option is not used, secure_delete defaults to off. When this option is present, secure_delete defaults to on.<br><br>The secure_delete setting causes deleted content to be overwritten with zeros. There is a small performance penalty since additional I/O must occur.<br><br>On the other hand, secure_delete can prevent fragments of sensitive information from lingering in unused parts of the database file after it has been deleted. See the documentation on the secure_delete pragma for additional information |
|
||||
| Secure Delete (FAST) | sqlite_secure_delete_fast | For more information see [PRAGMA secure_delete](https://www.sqlite.org/pragma.html#pragma_secure_delete) |
|
||||
| Tracing / Debug | sqlite_trace | Activate trace functions |
|
||||
|
||||
# Compilation
|
||||
|
|
512
sqlite3.go
512
sqlite3.go
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
@ -779,36 +780,135 @@ func errorString(err Error) string {
|
|||
}
|
||||
|
||||
// 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.
|
||||
// test.db
|
||||
// file:test.db?cache=shared&mode=memory
|
||||
// :memory:
|
||||
// file::memory:
|
||||
//
|
||||
// mode
|
||||
// Access mode of the database.
|
||||
// https://www.sqlite.org/c3ref/open.html
|
||||
// Values:
|
||||
// - ro
|
||||
// - rw
|
||||
// - rwc
|
||||
// - memory
|
||||
//
|
||||
// shared
|
||||
// SQLite Shared-Cache Mode
|
||||
// https://www.sqlite.org/sharedcache.html
|
||||
// Values:
|
||||
// - shared
|
||||
// - private
|
||||
//
|
||||
// immutable=Boolean
|
||||
// The immutable parameter is a boolean query parameter that indicates
|
||||
// that the database file is stored on read-only media. When immutable is set,
|
||||
// SQLite assumes that the database file cannot be changed,
|
||||
// even by a process with higher privilege,
|
||||
// and so the database is opened read-only and all locking and change detection is disabled.
|
||||
// Caution: Setting the immutable property on a database file that
|
||||
// does in fact change can result in incorrect query results and/or SQLITE_CORRUPT errors.
|
||||
//
|
||||
// go-sqlite3 adds the following query parameters to those used by SQLite:
|
||||
// _loc=XXX
|
||||
// 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
|
||||
// Specify locking behavior for transactions. XXX can be "immediate",
|
||||
// "deferred", "exclusive".
|
||||
// _foreign_keys=X
|
||||
// Enable or disable enforcement of foreign keys. X can be 1 or 0.
|
||||
// _recursive_triggers=X
|
||||
// Enable or disable recursive triggers. X can be 1 or 0.
|
||||
// _mutex=XXX
|
||||
// Specify mutex mode. XXX can be "no", "full".
|
||||
//
|
||||
// _auto_vacuum=X | _vacuum=X
|
||||
// 0 | none - Auto Vacuum disabled
|
||||
// 1 | full - Auto Vacuum FULL
|
||||
// 2 | incremental - Auto Vacuum Incremental
|
||||
//
|
||||
// _busy_timeout=XXX"| _timeout=XXX
|
||||
// Specify value for sqlite3_busy_timeout.
|
||||
//
|
||||
// _case_sensitive_like=Boolean | _cslike=Boolean
|
||||
// https://www.sqlite.org/pragma.html#pragma_case_sensitive_like
|
||||
// Default or disabled the LIKE operation is case-insensitive.
|
||||
// When enabling this options behaviour of LIKE will become case-sensitive.
|
||||
//
|
||||
// _defer_foreign_keys=Boolean | _defer_fk=Boolean
|
||||
// Defer Foreign Keys until outermost transaction is committed.
|
||||
//
|
||||
// _foreign_keys=Boolean | _fk=Boolean
|
||||
// Enable or disable enforcement of foreign keys.
|
||||
//
|
||||
// _ignore_check_constraints=Boolean
|
||||
// This pragma enables or disables the enforcement of CHECK constraints.
|
||||
// The default setting is off, meaning that CHECK constraints are enforced by default.
|
||||
//
|
||||
// _journal_mode=MODE | _journal=MODE
|
||||
// Set journal mode for the databases associated with the current connection.
|
||||
// https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
//
|
||||
// _locking_mode=X | _locking=X
|
||||
// Sets the database connection locking-mode.
|
||||
// The locking-mode is either NORMAL or EXCLUSIVE.
|
||||
// https://www.sqlite.org/pragma.html#pragma_locking_mode
|
||||
//
|
||||
// _query_only=Boolean
|
||||
// The query_only pragma prevents all changes to database files when enabled.
|
||||
//
|
||||
// _recursive_triggers=Boolean | _rt=Boolean
|
||||
// Enable or disable recursive triggers.
|
||||
//
|
||||
// _secure_delete=Boolean|FAST
|
||||
// When secure_delete is on, SQLite overwrites deleted content with zeros.
|
||||
// https://www.sqlite.org/pragma.html#pragma_secure_delete
|
||||
//
|
||||
// _synchronous=X | _sync=X
|
||||
// Change the setting of the "synchronous" flag.
|
||||
// https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
//
|
||||
// _writable_schema=Boolean
|
||||
// When this pragma is on, the SQLITE_MASTER tables in which database
|
||||
// can be changed using ordinary UPDATE, INSERT, and DELETE statements.
|
||||
// Warning: misuse of this pragma can easily result in a corrupt database file.
|
||||
//
|
||||
//
|
||||
func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
if C.sqlite3_threadsafe() == 0 {
|
||||
return nil, errors.New("sqlite library was not compiled for thread-safe operation")
|
||||
}
|
||||
|
||||
var pkey string
|
||||
|
||||
// Options
|
||||
var loc *time.Location
|
||||
txlock := "BEGIN"
|
||||
busyTimeout := 5000
|
||||
foreignKeys := -1
|
||||
recursiveTriggers := -1
|
||||
mutex := C.int(C.SQLITE_OPEN_FULLMUTEX)
|
||||
txlock := "BEGIN"
|
||||
|
||||
// PRAGMA's
|
||||
autoVacuum := -1
|
||||
busyTimeout := 5000
|
||||
caseSensitiveLike := -1
|
||||
deferForeignKeys := -1
|
||||
foreignKeys := -1
|
||||
ignoreCheckConstraints := -1
|
||||
journalMode := "DELETE"
|
||||
lockingMode := "NORMAL"
|
||||
queryOnly := -1
|
||||
recursiveTriggers := -1
|
||||
secureDelete := "DEFAULT"
|
||||
synchronousMode := "NORMAL"
|
||||
writableSchema := -1
|
||||
|
||||
pos := strings.IndexRune(dsn, '?')
|
||||
if pos >= 1 {
|
||||
params, err := url.ParseQuery(dsn[pos+1:])
|
||||
|
@ -818,9 +918,10 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
|||
|
||||
// _loc
|
||||
if val := params.Get("_loc"); val != "" {
|
||||
if val == "auto" {
|
||||
switch strings.ToLower(val) {
|
||||
case "auto":
|
||||
loc = time.Local
|
||||
} else {
|
||||
default:
|
||||
loc, err = time.LoadLocation(val)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invalid _loc: %v: %v", val, err)
|
||||
|
@ -828,18 +929,21 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// _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)
|
||||
// _mutex
|
||||
if val := params.Get("_mutex"); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "no":
|
||||
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
|
||||
if val := params.Get("_txlock"); val != "" {
|
||||
switch val {
|
||||
switch strings.ToLower(val) {
|
||||
case "immediate":
|
||||
txlock = "BEGIN IMMEDIATE"
|
||||
case "exclusive":
|
||||
|
@ -851,39 +955,262 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// _foreign_keys
|
||||
if val := params.Get("_foreign_keys"); val != "" {
|
||||
switch val {
|
||||
case "1":
|
||||
foreignKeys = 1
|
||||
case "0":
|
||||
// Auto Vacuum (_vacuum)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_auto_vacuum
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_auto_vacuum"]; ok {
|
||||
pkey = "_auto_vacuum"
|
||||
}
|
||||
if _, ok := params["_vacuum"]; ok {
|
||||
pkey = "_vacuum"
|
||||
}
|
||||
if val := params.Get(pkey); 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 _auto_vacuum: %v, expecting value of '0 NONE 1 FULL 2 INCREMENTAL'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Busy Timeout (_busy_timeout)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_busy_timeout
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_busy_timeout"]; ok {
|
||||
pkey = "_busy_timeout"
|
||||
}
|
||||
if _, ok := params["_timeout"]; ok {
|
||||
pkey = "_timeout"
|
||||
}
|
||||
if val := params.Get(pkey); 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)
|
||||
}
|
||||
|
||||
// Case Sensitive Like (_cslike)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_case_sensitive_like
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_case_sensitive_like"]; ok {
|
||||
pkey = "_case_sensitive_like"
|
||||
}
|
||||
if _, ok := params["_cslike"]; ok {
|
||||
pkey = "_cslike"
|
||||
}
|
||||
if val := params.Get(pkey); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
caseSensitiveLike = 0
|
||||
case "1", "yes", "true", "on":
|
||||
caseSensitiveLike = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _case_sensitive_like: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Defer Foreign Keys (_defer_foreign_keys | _defer_fk)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_defer_foreign_keys
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_defer_foreign_keys"]; ok {
|
||||
pkey = "_defer_foreign_keys"
|
||||
}
|
||||
if _, ok := params["_defer_fk"]; ok {
|
||||
pkey = "_defer_fk"
|
||||
}
|
||||
if val := params.Get(pkey); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
deferForeignKeys = 0
|
||||
case "1", "yes", "true", "on":
|
||||
deferForeignKeys = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _defer_foreign_keys: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Foreign Keys (_foreign_keys | _fk)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_foreign_keys
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_foreign_keys"]; ok {
|
||||
pkey = "_foreign_keys"
|
||||
}
|
||||
if _, ok := params["_fk"]; ok {
|
||||
pkey = "_fk"
|
||||
}
|
||||
if val := params.Get(pkey); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
foreignKeys = 0
|
||||
case "1", "yes", "true", "on":
|
||||
foreignKeys = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _foreign_keys: %v", val)
|
||||
return nil, fmt.Errorf("Invalid _foreign_keys: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// _recursive_triggers
|
||||
if val := params.Get("_recursive_triggers"); val != "" {
|
||||
switch val {
|
||||
case "1":
|
||||
recursiveTriggers = 1
|
||||
case "0":
|
||||
// Ignore CHECK Constrains (_ignore_check_constraints)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_ignore_check_constraints
|
||||
//
|
||||
if val := params.Get("_ignore_check_constraints"); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
ignoreCheckConstraints = 0
|
||||
case "1", "yes", "true", "on":
|
||||
ignoreCheckConstraints = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _ignore_check_constraints: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Journal Mode (_journal_mode | _journal)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_journal_mode
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_journal_mode"]; ok {
|
||||
pkey = "_journal_mode"
|
||||
}
|
||||
if _, ok := params["_journal"]; ok {
|
||||
pkey = "_journal"
|
||||
}
|
||||
if val := params.Get(pkey); val != "" {
|
||||
switch strings.ToUpper(val) {
|
||||
case "DELETE", "TRUNCATE", "PERSIST", "MEMORY", "OFF":
|
||||
journalMode = strings.ToUpper(val)
|
||||
case "WAL":
|
||||
journalMode = strings.ToUpper(val)
|
||||
|
||||
// For WAL Mode set Synchronous Mode to 'NORMAL'
|
||||
// See https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
synchronousMode = "NORMAL"
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _journal: %v, expecting value of 'DELETE TRUNCATE PERSIST MEMORY WAL OFF'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Locking Mode (_locking)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_locking_mode
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_locking_mode"]; ok {
|
||||
pkey = "_locking_mode"
|
||||
}
|
||||
if _, ok := params["_locking"]; ok {
|
||||
pkey = "_locking"
|
||||
}
|
||||
if val := params.Get("_locking"); val != "" {
|
||||
switch strings.ToUpper(val) {
|
||||
case "NORMAL", "EXCLUSIVE":
|
||||
lockingMode = strings.ToUpper(val)
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _locking_mode: %v, expecting value of 'NORMAL EXCLUSIVE", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Query Only (_query_only)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_query_only
|
||||
//
|
||||
if val := params.Get("_query_only"); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
queryOnly = 0
|
||||
case "1", "yes", "true", "on":
|
||||
queryOnly = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _query_only: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive Triggers (_recursive_triggers)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_recursive_triggers
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_recursive_triggers"]; ok {
|
||||
pkey = "_recursive_triggers"
|
||||
}
|
||||
if _, ok := params["_rt"]; ok {
|
||||
pkey = "_rt"
|
||||
}
|
||||
if val := params.Get(pkey); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
recursiveTriggers = 0
|
||||
case "1", "yes", "true", "on":
|
||||
recursiveTriggers = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _recursive_triggers: %v", val)
|
||||
return nil, fmt.Errorf("Invalid _recursive_triggers: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// _mutex
|
||||
if val := params.Get("_mutex"); val != "" {
|
||||
switch val {
|
||||
case "no":
|
||||
mutex = C.SQLITE_OPEN_NOMUTEX
|
||||
case "full":
|
||||
mutex = C.SQLITE_OPEN_FULLMUTEX
|
||||
// Secure Delete (_secure_delete)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_secure_delete
|
||||
//
|
||||
if val := params.Get("_secure_delete"); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
secureDelete = "OFF"
|
||||
case "1", "yes", "true", "on":
|
||||
secureDelete = "ON"
|
||||
case "fast":
|
||||
secureDelete = "FAST"
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _mutex: %v", val)
|
||||
return nil, fmt.Errorf("Invalid _secure_delete: %v, expecting boolean value of '0 1 false true no yes off on fast'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronous Mode (_synchronous | _sync)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_synchronous
|
||||
//
|
||||
pkey = "" // Reset pkey
|
||||
if _, ok := params["_synchronous"]; ok {
|
||||
pkey = "_synchronous"
|
||||
}
|
||||
if _, ok := params["_sync"]; ok {
|
||||
pkey = "_sync"
|
||||
}
|
||||
if val := params.Get(pkey); val != "" {
|
||||
switch strings.ToUpper(val) {
|
||||
case "0", "OFF", "1", "NORMAL", "2", "FULL", "3", "EXTRA":
|
||||
synchronousMode = strings.ToUpper(val)
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _synchronous: %v, expecting value of '0 OFF 1 NORMAL 2 FULL 3 EXTRA'", val)
|
||||
}
|
||||
}
|
||||
|
||||
// Writable Schema (_writeable_schema)
|
||||
//
|
||||
// https://www.sqlite.org/pragma.html#pragma_writeable_schema
|
||||
//
|
||||
if val := params.Get("_writable_schema"); val != "" {
|
||||
switch strings.ToLower(val) {
|
||||
case "0", "no", "false", "off":
|
||||
writableSchema = 0
|
||||
case "1", "yes", "true", "on":
|
||||
writableSchema = 1
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _writable_schema: %v, expecting boolean value of '0 1 false true no yes off on'", val)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -920,24 +1247,101 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
if foreignKeys == 0 {
|
||||
if err := exec("PRAGMA foreign_keys = OFF;"); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
} else if foreignKeys == 1 {
|
||||
if err := exec("PRAGMA foreign_keys = ON;"); err != nil {
|
||||
|
||||
// Auto Vacuum
|
||||
if autoVacuum > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA auto_vacuum = %d;", autoVacuum)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if recursiveTriggers == 0 {
|
||||
if err := exec("PRAGMA recursive_triggers = OFF;"); err != nil {
|
||||
|
||||
// Case Sensitive LIKE
|
||||
if caseSensitiveLike > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA case_sensitive_like = %d;", caseSensitiveLike)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
} else if recursiveTriggers == 1 {
|
||||
if err := exec("PRAGMA recursive_triggers = ON;"); err != nil {
|
||||
}
|
||||
|
||||
// Defer Foreign Keys
|
||||
if deferForeignKeys > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA defer_foreign_keys = %d;", deferForeignKeys)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Forgein Keys
|
||||
if foreignKeys > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA foreign_keys = %d;", foreignKeys)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore CHECK Constraints
|
||||
if ignoreCheckConstraints > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA ignore_check_constraints = %d;", ignoreCheckConstraints)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Journal Mode
|
||||
// Because default Journal Mode is DELETE this PRAGMA can always be executed.
|
||||
if err := exec(fmt.Sprintf("PRAGMA journal_mode = %s;", journalMode)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Locking Mode
|
||||
// Because the default is NORMAL and this is not changed in this package
|
||||
// by using the compile time SQLITE_DEFAULT_LOCKING_MODE this PRAGMA can always be executed
|
||||
if err := exec(fmt.Sprintf("PRAGMA locking_mode = %s;", lockingMode)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Query Only
|
||||
if queryOnly > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA query_only = %d;", queryOnly)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive Triggers
|
||||
if recursiveTriggers > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA recursive_triggers = %d;", recursiveTriggers)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Secure Delete
|
||||
//
|
||||
// Because this package can set the compile time flag SQLITE_SECURE_DELETE with a build tag
|
||||
// the default value for secureDelete var is 'DEFAULT' this way
|
||||
// you can compile with secure_delete 'ON' and disable it for a specific database connection.
|
||||
if secureDelete != "DEFAULT" {
|
||||
if err := exec(fmt.Sprintf("PRAGMA secure_delete = %s;", secureDelete)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronous Mode
|
||||
//
|
||||
// Because default is NORMAL this statement is always executed
|
||||
if err := exec(fmt.Sprintf("PRAGMA synchronous = %s;", synchronousMode)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Writable Schema
|
||||
if writableSchema > -1 {
|
||||
if err := exec(fmt.Sprintf("PRAGMA writable_schema = %d;", writableSchema)); err != nil {
|
||||
C.sqlite3_close_v2(db)
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
@ -8,7 +9,7 @@
|
|||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_SECURE_DELETE
|
||||
#cgo CFLAGS: -DSQLITE_SECURE_DELETE=1
|
||||
#cgo LDFLAGS: -lm
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build sqlite_secure_delete_fast
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_SECURE_DELETE=FAST
|
||||
#cgo LDFLAGS: -lm
|
||||
*/
|
||||
import "C"
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
// Copyright (C) 2018 G.J.R. Timmer <gjr.timmer@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
|
Loading…
Reference in New Issue