121 lines
4.6 KiB
Go
121 lines
4.6 KiB
Go
// Copyright 2025 The Sqlite Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package sqlite // import "modernc.org/sqlite"
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"fmt"
|
|
|
|
"modernc.org/sqlite/vtab"
|
|
)
|
|
|
|
// Driver implements database/sql/driver.Driver.
|
|
type Driver struct {
|
|
// user defined functions that are added to every new connection on Open
|
|
udfs map[string]*userDefinedFunction
|
|
// collations that are added to every new connection on Open
|
|
collations map[string]*collation
|
|
// connection hooks are called after a connection is opened
|
|
connectionHooks []ConnectionHookFn
|
|
// modules holds registered virtual table modules that should be added to
|
|
// every new connection on Open.
|
|
modules map[string]vtab.Module
|
|
}
|
|
|
|
var d = &Driver{
|
|
udfs: make(map[string]*userDefinedFunction, 0),
|
|
collations: make(map[string]*collation, 0),
|
|
connectionHooks: make([]ConnectionHookFn, 0),
|
|
modules: make(map[string]vtab.Module, 0),
|
|
}
|
|
|
|
func newDriver() *Driver { return d }
|
|
|
|
// Open returns a new connection to the database. The name is a string in a
|
|
// driver-specific format.
|
|
//
|
|
// Open may return a cached connection (one previously closed), but doing so is
|
|
// unnecessary; the sql package maintains a pool of idle connections for
|
|
// efficient re-use.
|
|
//
|
|
// The returned connection is only used by one goroutine at a time.
|
|
//
|
|
// The name may be a filename, e.g., "/tmp/mydata.sqlite", or a URI, in which
|
|
// case it may include a '?' followed by one or more query parameters.
|
|
// For example, "file:///tmp/mydata.sqlite?_pragma=foreign_keys(1)&_time_format=sqlite".
|
|
// The supported query parameters are:
|
|
//
|
|
// _pragma: Each value will be run as a "PRAGMA ..." statement (with the PRAGMA
|
|
// keyword added for you). May be specified more than once, '&'-separated. For more
|
|
// information on supported PRAGMAs see: https://www.sqlite.org/pragma.html
|
|
//
|
|
// _time_format: The name of a format to use when writing time values to the
|
|
// database. Currently the only supported value is "sqlite", which corresponds
|
|
// to format 7 from https://www.sqlite.org/lang_datefunc.html#time_values,
|
|
// including the timezone specifier. If this parameter is not specified, then
|
|
// the default String() format will be used.
|
|
//
|
|
// _time_integer_format: The name of a integer format to use when writing time values.
|
|
// By default, the time is stored as string and the format can be set with _time_format
|
|
// parameter. If _time_integer_format is set, the time will be stored as an integer and
|
|
// the integer value will depend on the integer format.
|
|
// If you decide to set both _time_format and _time_integer_format, the time will be
|
|
// converted as integer and the _time_format value will be ignored.
|
|
// Currently the supported value are "unix","unix_milli", "unix_micro" and "unix_nano",
|
|
// which corresponds to seconds, milliseconds, microseconds or nanoseconds
|
|
// since unixepoch (1 January 1970 00:00:00 UTC).
|
|
//
|
|
// _inttotime: Enable conversion of time column (DATE, DATETIME,TIMESTAMP) from integer
|
|
// to time if the field contain integer (int64).
|
|
//
|
|
// _txlock: The locking behavior to use when beginning a transaction. May be
|
|
// "deferred" (the default), "immediate", or "exclusive" (case insensitive). See:
|
|
// https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
|
|
func (d *Driver) Open(name string) (conn driver.Conn, err error) {
|
|
if dmesgs {
|
|
defer func() {
|
|
dmesg("name %q: (driver.Conn %p, err %v)", name, conn, err)
|
|
}()
|
|
}
|
|
c, err := newConn(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, udf := range d.udfs {
|
|
if err = c.createFunctionInternal(udf); err != nil {
|
|
c.Close()
|
|
return nil, err
|
|
}
|
|
}
|
|
for _, coll := range d.collations {
|
|
if err = c.createCollationInternal(coll); err != nil {
|
|
c.Close()
|
|
return nil, err
|
|
}
|
|
}
|
|
for _, connHookFn := range d.connectionHooks {
|
|
if err = connHookFn(c, name); err != nil {
|
|
c.Close()
|
|
return nil, fmt.Errorf("connection hook: %w", err)
|
|
}
|
|
}
|
|
// Register any vtab modules with this connection.
|
|
// Note: vtab module registration applies to new connections only. If a
|
|
// module is registered after a connection has been opened, that existing
|
|
// connection will not see the module; open a new connection to use it.
|
|
if err := c.registerModules(); err != nil {
|
|
c.Close()
|
|
return nil, err
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
// RegisterConnectionHook registers a function to be called after each connection
|
|
// is opened. This is called after all the connection has been set up.
|
|
func (d *Driver) RegisterConnectionHook(fn ConnectionHookFn) {
|
|
d.connectionHooks = append(d.connectionHooks, fn)
|
|
}
|