Open vcabbage opened 1 year ago
+1
Having access to underlying connection object (*C.struct_sqlite3
) allows to register extensions built externally, a use-case I ran into when building sqlean.go
.
There I've managed to use reflect
package access conn.db
field from struct SQLiteConn
, like:
func init() {
sql.Register("sqlean", &sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
// db points to the underlying *C.struct_sqlite3
var db = reflect.Indirect(reflect.ValueOf(conn)).FieldByName("db").UnsafePointer()
return nil
},
})
}
But this rely on reflect
and, I feel, is a bit fragile (what if the layout or name of the field changes?)
@riyaz-ali I've been doing something similar and agree that it's fragile. FWIW, I also put in this guard as a best effort way of detecting changes instead of silently corrupting memory or panicking.
// Check the field is a *C.sqlite3. C types are unusual in that the
// reflect.Types can't be compared directly due to having the namespace of
// the importing package. This appears to be the most reliable way to
// validate the type in this case.
field := reflect.ValueOf(c).Elem().FieldByName("db")
if field.Type().String() != "*sqlite3._Ctype_struct_sqlite3" {
return nil, fmt.Errorf(`field "db" %s not *C.sqlite3`, field.Type())
}
Background
Spatialite can be initialized in two ways. Most commonly
mod_spatialite
is loaded via sqlite APIs, which eventually usedlopen
to dynamically load the shared library. This doesn't allow for statically linking spatialite. Additionally if sqlite is statically linked it can't load extensions becausedlopen
doesn't work.The other option is to link
libspatialite
into the binary and initialize spatialite on thesqlite3
handle via spatialite's C API.Roughly:
This method does allow for static linking.
Request
I have a need to build fully static binaries including sqlite/spatialite. I don't think it would be reasonable to ask that this be directly supported in this library since spatialite isn't designed to be self contained and easy to compile like the sqlite amalgamation. It would be helpful to be able to access the
*C.sqlite3
struct without forking the library though.Would you consider providing a way to access
*C.sqlite3
from the connection? Even if it's a method likeUnsafeDontAskForSupport() *C.sqlite3
:grinning:.Thanks for the library and considering this request!
Aside: If you're wondering about the potential leak of the allocation by
C.spatialite_alloc_connection()
, my solution is to wrap the go-sqlite3driver.Driver
anddriver.Conn
so that it can be freed when the connection is closed.