package driver

Import Path
	github.com/ncruces/go-sqlite3/driver (on go.dev)

Dependency Relation
	imports 14 packages, and imported by one package

Involved Source Files Package driver provides a database/sql driver for SQLite. Importing package driver registers a [database/sql] driver named "sqlite3". You may also need to import package embed. import _ "github.com/ncruces/go-sqlite3/driver" import _ "github.com/ncruces/go-sqlite3/embed" The data source name for "sqlite3" databases can be a filename or a "file:" [URI]. # Default transaction mode The [TRANSACTION] mode can be specified using "_txlock": sql.Open("sqlite3", "file:demo.db?_txlock=immediate") Possible values are: "deferred" (the default), "immediate", "exclusive". Regardless of "_txlock": - a [linearizable] transaction is always "exclusive"; - a [serializable] transaction is always "immediate"; - a [read-only] transaction is always "deferred". # Datatypes In SQLite SQLite is dynamically typed. Columns can mostly hold any value regardless of their declared type. SQLite supports most [driver.Value] types out of the box, but bool and [time.Time] require special care. Booleans can be stored on any column type and scanned back to a *bool. However, if scanned to a *any, booleans may either become an int64, string or bool, depending on the declared type of the column. If you use BOOLEAN for your column type, 1 and 0 will always scan as true and false. # Working with time Time values can similarly be stored on any column type. The time encoding/decoding format can be specified using "_timefmt": sql.Open("sqlite3", "file:demo.db?_timefmt=sqlite") Special values are: "auto" (the default), "sqlite", "rfc3339"; - "auto" encodes as RFC 3339 and decodes any [format] supported by SQLite; - "sqlite" encodes as SQLite and decodes any [format] supported by SQLite; - "rfc3339" encodes and decodes RFC 3339 only. You can also set "_timefmt" to an arbitrary [sqlite3.TimeFormat] or [time.Layout]. If you encode as RFC 3339 (the default), consider using the TIME [collating sequence] to produce time-ordered sequences. If you encode as RFC 3339 (the default), time values will scan back to a *time.Time unless your column type is TEXT. Otherwise, if scanned to a *any, time values may either become an int64, float64 or string, depending on the time format and declared type of the column. If you use DATE, TIME, DATETIME, or TIMESTAMP for your column type, "_timefmt" will be used to decode values. To scan values in custom formats, [sqlite3.TimeFormat.Scanner] may be helpful. To bind values in custom formats, [sqlite3.TimeFormat.Encode] them before binding. When using a custom time struct, you'll have to implement [database/sql/driver.Valuer] and [database/sql.Scanner]. The Value method should ideally encode to a time [format] supported by SQLite. This ensures SQL date and time functions work as they should, and that your schema works with other SQLite tools. [sqlite3.TimeFormat.Encode] may help. The Scan method needs to take into account that the value it receives can be of differing types. It can already be a [time.Time], if the driver decoded the value according to "_timefmt" rules. Or it can be a: string, int64, float64, []byte, or nil, depending on the column type and whoever wrote the value. [sqlite3.TimeFormat.Decode] may help. # Setting PRAGMAs [PRAGMA] statements can be specified using "_pragma": sql.Open("sqlite3", "file:demo.db?_pragma=busy_timeout(10000)") If no PRAGMAs are specified, a busy timeout of 1 minute is set. Order matters: encryption keys, busy timeout and locking mode should be the first PRAGMAs set, in that order. savepoint.go time.go util.go
Code Examples //go:build linux || darwin || windows || freebsd || openbsd || netbsd || dragonfly || illumos || sqlite3_flock || sqlite3_dotlk package main // Adapted from: https://go.dev/doc/tutorial/database-access import ( "database/sql" "fmt" "log" "os" _ "github.com/ncruces/go-sqlite3/driver" _ "github.com/ncruces/go-sqlite3/embed" _ "github.com/ncruces/go-sqlite3/vfs/memdb" ) var db *sql.DB type Album struct { ID int64 Title string Artist string Price float32 } func main() { // Get a database handle. var err error db, err = sql.Open("sqlite3", "./recordings.db") if err != nil { log.Fatal(err) } defer os.Remove("./recordings.db") defer db.Close() // Create a table with some data in it. err = albumsSetup() if err != nil { log.Fatal(err) } albums, err := albumsByArtist("John Coltrane") if err != nil { log.Fatal(err) } fmt.Printf("Albums found: %v\n", albums) // Hard-code ID 2 here to test the query. alb, err := albumByID(2) if err != nil { log.Fatal(err) } fmt.Printf("Album found: %v\n", alb) albID, err := addAlbum(Album{ Title: "The Modern Sound of Betty Carter", Artist: "Betty Carter", Price: 49.99, }) if err != nil { log.Fatal(err) } fmt.Printf("ID of added album: %v\n", albID) } func albumsSetup() error { _, err := db.Exec(` DROP TABLE IF EXISTS album; CREATE TABLE album ( id INTEGER PRIMARY KEY AUTOINCREMENT, title VARCHAR(128) NOT NULL, artist VARCHAR(255) NOT NULL, price DECIMAL(5,2) NOT NULL ); `) if err != nil { return err } _, err = db.Exec(` INSERT INTO album (title, artist, price) VALUES ('Blue Train', 'John Coltrane', 56.99), ('Giant Steps', 'John Coltrane', 63.99), ('Jeru', 'Gerry Mulligan', 17.99), ('Sarah Vaughan', 'Sarah Vaughan', 34.98) `) if err != nil { return err } return nil } // albumsByArtist queries for albums that have the specified artist name. func albumsByArtist(name string) ([]Album, error) { // An albums slice to hold data from returned rows. var albums []Album rows, err := db.Query("SELECT * FROM album WHERE artist = ?", name) if err != nil { return nil, fmt.Errorf("albumsByArtist %q: %w", name, err) } defer rows.Close() // Loop through rows, using Scan to assign column data to struct fields. for rows.Next() { var alb Album if err := rows.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil { return nil, fmt.Errorf("albumsByArtist %q: %w", name, err) } albums = append(albums, alb) } if err := rows.Err(); err != nil { return nil, fmt.Errorf("albumsByArtist %q: %w", name, err) } return albums, nil } // albumByID queries for the album with the specified ID. func albumByID(id int64) (Album, error) { // An album to hold data from the returned row. var alb Album row := db.QueryRow("SELECT * FROM album WHERE id = ?", id) if err := row.Scan(&alb.ID, &alb.Title, &alb.Artist, &alb.Price); err != nil { if err == sql.ErrNoRows { return alb, fmt.Errorf("albumsById %d: no such album", id) } return alb, fmt.Errorf("albumsById %d: %w", id, err) } return alb, nil } // addAlbum adds the specified album to the database, // returning the album ID of the new entry func addAlbum(alb Album) (int64, error) { result, err := db.Exec("INSERT INTO album (title, artist, price) VALUES (?, ?, ?)", alb.Title, alb.Artist, alb.Price) if err != nil { return 0, fmt.Errorf("addAlbum: %w", err) } id, err := result.LastInsertId() if err != nil { return 0, fmt.Errorf("addAlbum: %w", err) } return id, nil }
Package-Level Type Names (total 2)
/* sort by: | */
Conn is implemented by the SQLite [database/sql] driver connections. It can be used to access SQLite features like [online backup]: db, err := driver.Open("temp.db") if err != nil { log.Fatal(err) } defer db.Close() conn, err := db.Conn(context.TODO()) if err != nil { log.Fatal(err) } defer conn.Close() err = conn.Raw(func(driverConn any) error { conn := driverConn.(driver.Conn) return conn.Raw().Backup("main", "backup.db") }) if err != nil { log.Fatal(err) } Begin starts and returns a new transaction. Deprecated: Drivers should implement ConnBeginTx instead (or additionally). BeginTx starts and returns a new transaction. If the context is canceled by the user the sql package will call Tx.Rollback before discarding and closing the connection. This must check opts.Isolation to determine if there is a set isolation level. If the driver does not support a non-default level and one is set or if there is a non-default isolation level that is not supported, an error must be returned. This must also check opts.ReadOnly to determine if the read-only value is true to either set the read-only transaction property if supported or return an error if it is not supported. Close invalidates and potentially stops any current prepared statements and transactions, marking this connection as no longer in use. Because the sql package maintains a free pool of connections and only calls Close when there's a surplus of idle connections, it shouldn't be necessary for drivers to do their own connection caching. Drivers must ensure all network calls made by Close do not block indefinitely (e.g. apply a timeout). Prepare returns a prepared statement, bound to this connection. PrepareContext returns a prepared statement, bound to this connection. context is for the preparation of the statement, it must not store the context within the statement itself. ( Conn) Raw() *sqlite3.Conn Conn : github.com/prometheus/common/expfmt.Closer Conn : database/sql/driver.Conn Conn : database/sql/driver.ConnBeginTx Conn : database/sql/driver.ConnPrepareContext Conn : io.Closer
SQLite implements [database/sql/driver.Driver]. Open implements [database/sql/driver.Driver]. OpenConnector implements [database/sql/driver.DriverContext]. *SQLite : database/sql/driver.Driver *SQLite : database/sql/driver.DriverContext
Package-Level Functions (total 2)
Open opens the SQLite database specified by dataSourceName as a [database/sql.DB]. Open accepts zero, one, or two callbacks (nil callbacks are ignored). The first callback is called when the driver opens a new connection. The second callback is called before the driver closes a connection. The [sqlite3.Conn] can be used to execute queries, register functions, etc.
Savepoint establishes a new transaction savepoint. https://sqlite.org/lang_savepoint.html