// Open database and return a new connection. // You can specify DSN string with URI filename. // test.db // file:test.db?cache=shared&mode=memory // :memory: // file::memory: 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 db *C.sqlite3 name := C.CString(dsn) defer C.free(unsafe.Pointer(name)) rv := C._sqlite3_open_v2(name, &db, C.SQLITE_OPEN_FULLMUTEX| C.SQLITE_OPEN_READWRITE| C.SQLITE_OPEN_CREATE, nil) if rv != 0 { return nil, Error{Code: ErrNo(rv)} } if db == nil { return nil, errors.New("sqlite succeeded without returning a database") } rv = C.sqlite3_busy_timeout(db, 5000) if rv != C.SQLITE_OK { return nil, Error{Code: ErrNo(rv)} } conn := &SQLiteConn{db} if len(d.Extensions) > 0 { rv = C.sqlite3_enable_load_extension(db, 1) if rv != C.SQLITE_OK { return nil, errors.New(C.GoString(C.sqlite3_errmsg(db))) } for _, extension := range d.Extensions { cext := C.CString(extension) defer C.free(unsafe.Pointer(cext)) rv = C.sqlite3_load_extension(db, cext, nil, nil) if rv != C.SQLITE_OK { return nil, errors.New(C.GoString(C.sqlite3_errmsg(db))) } } rv = C.sqlite3_enable_load_extension(db, 0) if rv != C.SQLITE_OK { return nil, errors.New(C.GoString(C.sqlite3_errmsg(db))) } } if d.ConnectHook != nil { if err := d.ConnectHook(conn); err != nil { return nil, err } } runtime.SetFinalizer(conn, (*SQLiteConn).Close) return conn, nil }
// LoadExtension loads an extension // (See http://sqlite.org/c3ref/load_extension.html) func (c *Conn) LoadExtension(file string, proc ...string) error { cfile := C.CString(file) defer C.free(unsafe.Pointer(cfile)) var cproc *C.char if len(proc) > 0 { cproc = C.CString(proc[0]) defer C.free(unsafe.Pointer(cproc)) } var errMsg *C.char rv := C.sqlite3_load_extension(c.db, cfile, cproc, &errMsg) if rv != C.SQLITE_OK { defer C.sqlite3_free(unsafe.Pointer(errMsg)) return c.error(rv, C.GoString(errMsg)) } return nil }
func (c *SQLiteConn) loadExtensions(extensions []string) error { rv := C.sqlite3_enable_load_extension(c.db, 1) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } for _, extension := range extensions { cext := C.CString(extension) defer C.free(unsafe.Pointer(cext)) rv = C.sqlite3_load_extension(c.db, cext, nil, nil) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } } rv = C.sqlite3_enable_load_extension(c.db, 0) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } return nil }
// LoadExtension load the sqlite3 extension. func (c *SQLiteConn) LoadExtension(lib string, entry string) error { rv := C.sqlite3_enable_load_extension(c.db, 1) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } clib := C.CString(lib) defer C.free(unsafe.Pointer(clib)) centry := C.CString(entry) defer C.free(unsafe.Pointer(centry)) rv = C.sqlite3_load_extension(c.db, clib, centry, nil) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } rv = C.sqlite3_enable_load_extension(c.db, 0) if rv != C.SQLITE_OK { return errors.New(C.GoString(C.sqlite3_errmsg(c.db))) } return nil }
// Open database and return a new connection. // You can specify DSN string with URI filename. // test.db // file:test.db?cache=shared&mode=memory // :memory: // file::memory: // go-sqlite handle especially query parameters. // _loc=XXX // Specify location of time format. It's possible to specify "auto". // _busy_timeout=XXX // Specify value for sqlite3_busy_timeout. // _txlock=XXX // Specify locking behavior for transactions. XXX can be "immediate", // "deferred", "exclusive". 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 loc *time.Location txlock := "BEGIN" busy_timeout := 5000 pos := strings.IndexRune(dsn, '?') if pos >= 1 { params, err := url.ParseQuery(dsn[pos+1:]) if err != nil { return nil, err } // _loc if val := params.Get("_loc"); val != "" { if val == "auto" { loc = time.Local } else { loc, err = time.LoadLocation(val) if err != nil { return nil, fmt.Errorf("Invalid _loc: %v: %v", val, err) } } } // _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) } busy_timeout = int(iv) } // _txlock if val := params.Get("_txlock"); val != "" { switch val { case "immediate": txlock = "BEGIN IMMEDIATE" case "exclusive": txlock = "BEGIN EXCLUSIVE" case "deferred": txlock = "BEGIN" default: return nil, fmt.Errorf("Invalid _txlock: %v", val) } } if !strings.HasPrefix(dsn, "file:") { dsn = dsn[:pos] } } var db *C.sqlite3 name := C.CString(dsn) defer C.free(unsafe.Pointer(name)) rv := C._sqlite3_open_v2(name, &db, C.SQLITE_OPEN_FULLMUTEX| C.SQLITE_OPEN_READWRITE| C.SQLITE_OPEN_CREATE, nil) if rv != 0 { return nil, Error{Code: ErrNo(rv)} } if db == nil { return nil, errors.New("sqlite succeeded without returning a database") } rv = C.sqlite3_busy_timeout(db, C.int(busy_timeout)) if rv != C.SQLITE_OK { return nil, Error{Code: ErrNo(rv)} } conn := &SQLiteConn{db: db, loc: loc, txlock: txlock} if len(d.Extensions) > 0 { rv = C.sqlite3_enable_load_extension(db, 1) if rv != C.SQLITE_OK { return nil, errors.New(C.GoString(C.sqlite3_errmsg(db))) } for _, extension := range d.Extensions { cext := C.CString(extension) defer C.free(unsafe.Pointer(cext)) rv = C.sqlite3_load_extension(db, cext, nil, nil) if rv != C.SQLITE_OK { return nil, errors.New(C.GoString(C.sqlite3_errmsg(db))) } } rv = C.sqlite3_enable_load_extension(db, 0) if rv != C.SQLITE_OK { return nil, errors.New(C.GoString(C.sqlite3_errmsg(db))) } } if d.ConnectHook != nil { if err := d.ConnectHook(conn); err != nil { return nil, err } } runtime.SetFinalizer(conn, (*SQLiteConn).Close) return conn, nil }