Skip to content

Commit fead148

Browse files
committed
Add _foreign_keys connection parameter
Fixes mattn#377 Updates mattn#255
1 parent b2e4645 commit fead148

File tree

1 file changed

+43
-3
lines changed

1 file changed

+43
-3
lines changed

sqlite3.go

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,14 +400,18 @@ func (c *SQLiteConn) AutoCommit() bool {
400400
}
401401

402402
func (c *SQLiteConn) lastError() error {
403-
rv := C.sqlite3_errcode(c.db)
403+
return lastError(c.db)
404+
}
405+
406+
func lastError(db *C.sqlite3) error {
407+
rv := C.sqlite3_errcode(db)
404408
if rv == C.SQLITE_OK {
405409
return nil
406410
}
407411
return Error{
408412
Code: ErrNo(rv),
409-
ExtendedCode: ErrNoExtended(C.sqlite3_extended_errcode(c.db)),
410-
err: C.GoString(C.sqlite3_errmsg(c.db)),
413+
ExtendedCode: ErrNoExtended(C.sqlite3_extended_errcode(db)),
414+
err: C.GoString(C.sqlite3_errmsg(db)),
411415
}
412416
}
413417

@@ -537,6 +541,8 @@ func errorString(err Error) string {
537541
// _txlock=XXX
538542
// Specify locking behavior for transactions. XXX can be "immediate",
539543
// "deferred", "exclusive".
544+
// _foreign_keys=X
545+
// Enable or disable enforcement of foreign keys. X can be 1 or 0.
540546
func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
541547
if C.sqlite3_threadsafe() == 0 {
542548
return nil, errors.New("sqlite library was not compiled for thread-safe operation")
@@ -545,6 +551,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
545551
var loc *time.Location
546552
txlock := "BEGIN"
547553
busyTimeout := 5000
554+
foreignKeys := -1
548555
pos := strings.IndexRune(dsn, '?')
549556
if pos >= 1 {
550557
params, err := url.ParseQuery(dsn[pos+1:])
@@ -587,6 +594,18 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
587594
}
588595
}
589596

597+
// _foreign_keys
598+
if val := params.Get("_foreign_keys"); val != "" {
599+
switch val {
600+
case "1":
601+
foreignKeys = 1
602+
case "0":
603+
foreignKeys = 0
604+
default:
605+
return nil, fmt.Errorf("Invalid _foreign_keys: %v", val)
606+
}
607+
}
608+
590609
if !strings.HasPrefix(dsn, "file:") {
591610
dsn = dsn[:pos]
592611
}
@@ -612,6 +631,27 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
612631
return nil, Error{Code: ErrNo(rv)}
613632
}
614633

634+
exec := func(s string) error {
635+
cs := C.CString(s)
636+
rv := C.sqlite3_exec(db, cs, nil, nil, nil)
637+
C.free(unsafe.Pointer(cs))
638+
if rv != C.SQLITE_OK {
639+
return lastError(db)
640+
}
641+
return nil
642+
}
643+
if foreignKeys == 0 {
644+
if err := exec("PRAGMA foreign_keys = OFF;"); err != nil {
645+
C.sqlite3_close_v2(db)
646+
return nil, err
647+
}
648+
} else if foreignKeys == 1 {
649+
if err := exec("PRAGMA foreign_keys = ON;"); err != nil {
650+
C.sqlite3_close_v2(db)
651+
return nil, err
652+
}
653+
}
654+
615655
conn := &SQLiteConn{db: db, loc: loc, txlock: txlock}
616656

617657
if len(d.Extensions) > 0 {

0 commit comments

Comments
 (0)