Repository: mattn/go-sqlite3
Pull request #882 (2020-11-16 14:37:46)

doc.go: you can use Conn.Raw to get *SQLiteConn
This can be easier that registering a new driver, in some cases.
Add a test to verify that this works.


Patch:
diff --git a/doc.go b/doc.go
index c721f77..7a4fb6d 100644
--- a/doc.go
+++ b/doc.go
@@ -79,9 +79,8 @@ Then, you can use this extension.
 
 Connection Hook
 
-You can hook and inject your code when the connection is established. database/sql
-doesn't provide a way to get native go-sqlite3 interfaces. So if you want,
-you need to set ConnectHook and get the SQLiteConn.
+You can hook and inject your code when the connection is established by setting
+ConnectHook to get the SQLiteConn.
 
 	sql.Register("sqlite3_with_hook_example",
 			&sqlite3.SQLiteDriver{
@@ -91,21 +90,45 @@ you need to set ConnectHook and get the SQLiteConn.
 					},
 			})
 
+You can also use database/sql.Conn.Raw:
+
+	conn, err := db.Conn(context.Background())
+	// if err != nil { ... }
+	defer conn.Close()
+	err = conn.Raw(func (driverConn interface{}) error {
+		sqliteConn := driverConn.(*sqlite3.SQLiteConn)
+		// ... use sqliteConn
+	})
+	// if err != nil { ... }
+
 Go SQlite3 Extensions
 
-If you want to register Go functions as SQLite extension functions,
-call RegisterFunction from ConnectHook.
+If you want to register Go functions as SQLite extension functions
+you can make a custom driver by calling RegisterFunction from
+ConnectHook.
 
 	regex = func(re, s string) (bool, error) {
 		return regexp.MatchString(re, s)
 	}
-	sql.Register("sqlite3_with_go_func",
+	sql.Register("sqlite3_extended",
 			&sqlite3.SQLiteDriver{
 					ConnectHook: func(conn *sqlite3.SQLiteConn) error {
 						return conn.RegisterFunc("regexp", regex, true)
 					},
 			})
 
+You can then use the custom driver by passing its name to sql.Open.
+
+	var i int
+	conn, err := sql.Open("sqlite3_extended", "./foo.db")
+	if err != nil {
+		panic(err)
+	}
+	err = db.QueryRow(`SELECT regexp("foo.*", "seafood")`).Scan(&i)
+	if err != nil {
+		panic(err)
+	}
+
 See the documentation of RegisterFunc for more details.
 
 */


Test patch:
diff --git a/sqlite3_test.go b/sqlite3_test.go
index d5b0cea..fe367cf 100644
--- a/sqlite3_test.go
+++ b/sqlite3_test.go
@@ -9,6 +9,7 @@ package sqlite3
 
 import (
 	"bytes"
+	"context"
 	"database/sql"
 	"database/sql/driver"
 	"errors"
@@ -2352,3 +2353,32 @@ func benchmarkStmtRows(b *testing.B) {
 		}
 	}
 }
+
+func TestConnRawIsSQLiteConn(t *testing.T) {
+	db, err := sql.Open("sqlite3", ":memory:")
+	if err != nil {
+		t.Fatal("Failed to open db:", err)
+	}
+	defer db.Close()
+
+	conn, err := db.Conn(context.Background())
+	if err != nil {
+		t.Fatal("Failed to get conn:", err)
+	}
+	defer conn.Close()
+	err = conn.Raw(func(driverConn interface{}) error {
+		sqliteConn, ok := driverConn.(*SQLiteConn)
+		if !ok {
+			t.Errorf("driverConn type=%T; expected to be *SQLiteConn", driverConn)
+			return nil
+		}
+		// call a private SQLite API to confirm the raw conn "works"
+		if sqliteConn.AuthEnabled() {
+			t.Error("sqliteConn.AuthEnabled()=true; expected false")
+		}
+		return nil
+	})
+	if err != nil {
+		t.Error("conn.Raw() returned err:", err)
+	}
+}