sqlite3

package
v1.0.51 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2021 License: Apache-2.0 Imports: 22 Imported by: 0

README

sqlite3 package

This package provides a high-level interface for sqlite3 including connection pooling, transaction and execution management.

This package is part of a wider project, github.com/mutablelogic/go-sqlite. Please see the module documentation for more information.

Building

This module does not include a full copy of sqlite as part of the build process, but expect a pkgconfig file called sqlite3.pc to be present (and an existing set of header files and libraries to be available to link against, of course).

In order to locate the correct installation of sqlite3 use two environment variables:

  • PKG_CONFIG_PATH is used for locating sqlite3.pc
  • DYLD_LIBRARY_PATH is used for locating the dynamic library when testing and/or running

On Macintosh with homebrew, for example:

[bash] brew install sqlite3
[bash] git clone git@github.com:djthorpe/go-sqlite.git
[bash] cd go-sqlite
[bash] go mod tidy
[bash] SQLITE_LIB="/usr/local/opt/sqlite/lib"
[bash] PKG_CONFIG_PATH="${SQLITE_LIB}/pkgconfig" DYLD_LIBRARY_PATH="${SQLITE_LIB}" go test -v ./pkg/sqlite3

On Debian Linux you shouldn't need to locate the correct path to the sqlite3 library:

[bash] sudo apt install libsqlite3-dev
[bash] git clone git@github.com:djthorpe/go-sqlite.git
[bash] cd go-sqlite
[bash] go mod tidy
[bash] go test -v ./pkg/sqlite3

There are some examples in the cmd folder of the main repository on how to use the package, and various pseudo examples in this document.

Contributing & Distribution

Please do file feature requests and bugs here. The license is Apache 2 so feel free to redistribute. Redistributions in either source code or binary form must reproduce the copyright notice, and please link back to this repository for more information:

Copyright (c) 2021, David Thorpe, All rights reserved.

Overview

The package includes:

  • A Connection Pool for managing connections to sqlite3 databases;
  • A Connection for executing queries;
  • An Auth interface for managing authentication and authorization;
  • A Cache for managing prepared statements.

It's possible to create custom functions (both in a scalar and aggregate context) and use perform streaming read and write operations on large binary (BLOB) objects.

In order to create a connection pool, you can create a default pool using the NewPool method:

package main

import (
  sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
)

func main() {
  pool, err := sqlite3.NewPool(path, nil)
  if err != nil {
    panic(err)
  }
  defer pool.Close()

  // Onbtain a connection from pool, put back when done
  conn := pool.Get()
  defer pool.Put(conn)

  // Enumerate the tables in the database
  tables := conn.Tables()

  // ...
}

In this example, a database is opened and the Get method obtains a connection to the databaseand Put will return it to the pool. The Tables method enumerates the tables in the database. The following sections outline how to interact with the sqlite3 package in more detail.

Connection Pool

A Pool is a common pattern for managing connections to a database, where there is a limited number of connections available with concurrent accesses to the database. The pool can be created in two ways:

  1. sqlite3.NewPool(path string, errs chan<- error) (*Pool, error) creates a standard pool for a single database (referred to by file path or as :memory: for an in-memory database);
  2. sqlite3.OpenPool(config sqlite3.PoolConfig, errs chan<- error) (*Pool, error) creates a pool with a configuration; more information on the configuration can be found below.

In either case, the second argument can be nil or a channel for receiving errors. Errors are received in this way so that the pool method Get can return nil if an error occurs, but errors can still be reported for debugging.

Pool Configuration

By default the pool will create a maximum of 5 simultaneous connections to the database. However, you can use the NewConfig() method with options to alter the default configuration. For example,

package main

import (
  sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
)

func main() {
  cfg := sqlite3.NewConfig().SetMaxConnections(100)
  pool, err := sqlite3.OpenPool(cfg, nil)
  if err != nil {
    panic(err)
  }
  defer pool.Close()

  // ...
}

The different options to modify the default configuration are:

  • func (PoolConfig) WithAuth(SQAuth) sets the authentication and authorization interface for any executed statements. More information about this interface can be found in the section below.
  • func (PoolConfig) WithTrace(TraceFunc) sets a trace function for the pool, so that you can monitor the activity executing statements. More information about this can be found in the section below.
  • func (PoolConfig) WithMaxConnections(int) sets the maximum number of connections to the database. Setting a value of 0 will use the default number of connections.
  • func (PoolConfig) WithSchema(name, path string) adds a database schema to the connection pool. One schema should always be named main. Setting the path argument to :memory: will set the schema to an in-memory database, otherwise the schema will be read from disk.
Getting a Connection

Once you have created a pool, you can obtain a connection from the pool using the Get method, which should always be paired with a Put call:

package main

import (
  sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
)

func main() {
  pool, err := sqlite3.NewPool(":memory:", nil)
  if err != nil {
    panic(err)
  }
  defer pool.Close()

  // Get connection
  conn := pool.Get()
  if conn == nil {
    panic("No connection")
  }
  defer pool.Put(conn)

  // ...
}

The Get method may return nil if the maximum number of connections has been reached. Once a connection has been Put back into the pool, it should no longer be used (there is nothing presently to prevent use of a connection after it has been Put back, but it could be added in later).

Example code for reporting errors

In general you should pass a channel for receiving errors. Here is some sample code you can use for doing this:

func createErrorChannel() (chan<- error, context.CancelFunc) {
  var wg sync.WaitGroup
  errs := make(chan error)
  ctx, cancel := context.WithCancel(context.Background())
  wg.Add(1)
  go func() {
    defer wg.Done()
      for {
        select {
        case <-ctx.Done():
          close(errs)
          return
        case err := <-errs:
          if err != nil {
            // Replace the following line
            log.Print(err)
          }
        }
      }
  }()

  return errs, func() { cancel(); wg.Wait() }
}

The function will return the error channel and a cancel function. The cancel function should only be called after the pool has been closed to ensure that the pool does not try and report errors to a closed error channel.

Transactions and Queries

There are two connection methods for executing queries:

Execution outside a transaction

The function func (SQConnection) Exec(SQStatement, SQExecFunc) error executes a callback function with the result of the query. For example,

package main

import (
  sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
  . "github.com/mutablelogic/go-sqlite/pkg/sqlang"
)

func main() {
  // ...
  conn.Exec(Q("PRAGMA module_list"), func(row, cols []string) bool {
    fmt.Println(row)
    return false
  })
}

Use this method to run statements which don't need committing or rolling back on errors, or which only need text information returned.

Execution in a transaction

On the whole you will want to operate the database inside tansactions. In order to do this, call the function func (SQConnection) Do(context.Context, SQFlag, SQTxnFunc) error with a callback function of type SQTxnFunc as an argument. The signature of the transaction function is func (SQTransaction) error and if it returns any error, the transaction will be rolled back, otherwise any modifications within the transaction will be committed.

You can pass zero (0) for the SQFlag argument if you don't need to use any flags, or else pass any combination of the following flags:

  • SQLITE_TXN_DEFAULT Default (deferred) transaction flag (can be omitted if not needed)
  • SQLITE_TXN_IMMEDIATE Immediate transaction
  • SQLITE_TXN_EXCLUSIVE Exclusive transaction
  • SQLITE_TXN_NO_FOREIGNKEY_CONSTRAINTS Drop foreign key constraints within the transaction

More information about different types of transactions is documented here.

For example,

package main

import (
  sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
  . "github.com/mutablelogic/go-sqlite/pkg/sqlang"
)

func main() {
  // ...
  conn.Do(context.Background(),0,func(txn SQTransaction) error {
    if _, err := txn.Query(N("test").Insert().WithDefaultValues()); err != nil {
      return err
    }
    // Commit transaction
    return nil
  })
}

Custom Types

TODO

Custom Functions

TODO

Authentication and Authorization

TODO

Pool Status

There are two methods which can be used for getting and setting pool status:

  • func (SQPool) Cur() int returns the current number of connections in the pool;
  • func (SQPool) SetMax(n int) sets the maximum number of connections allowed in the pool. This will not affect the number of connections currently in the pool, however.

Reading and Writing Large Objects

TODO

Backup

TODO

Documentation

Overview

Package sqlite3 provides a high level interface for sqlite3, including pooled connections object serialization and transactions

Index

Constants

View Source
const (
	// DefaultFlags are the default flags for a new database connection
	DefaultFlags  = SQFlag(sqlite3.SQLITE_OPEN_CREATE | sqlite3.SQLITE_OPEN_READWRITE)
	DefaultSchema = sqlite3.DefaultSchema
)

Variables

This section is empty.

Functions

func NewProfileArray

func NewProfileArray(cap, samples int, age time.Duration) *profilearray

NewProfileArray returns a new set of profiles, up to "capacity" profiles, removing the oldest profiles based on age

func NewSampleArray

func NewSampleArray(cap int) *samplearray

NewSampleArray returns a new set of samples, up to "capacity" samples.

func Version

func Version() string

Types

type Conn

type Conn struct {
	sync.Mutex
	*sqlite3.ConnEx
	ConnCache
	// contains filtered or unexported fields
}

func New

func New(flags ...SQFlag) (*Conn, error)

New creates an in-memory database. Pass any flags to set open options. If no flags are provided, the default is to create a read/write database.

func OpenPath

func OpenPath(path string, flags SQFlag) (*Conn, error)

func (*Conn) Attach added in v1.0.51

func (conn *Conn) Attach(schema, path string) error

Attach database as schema. If path is empty then a new in-memory database is attached. If the path does not exist then it is created if the SQLITE_OPEN_CREATE flag is set.

func (*Conn) Close

func (conn *Conn) Close() error

func (*Conn) ColumnsForIndex

func (c *Conn) ColumnsForIndex(schema, index string) []string

ColumnsForIndex returns the indexes associated with a table

func (*Conn) ColumnsForTable

func (c *Conn) ColumnsForTable(schema, table string) []SQColumn

ColumnsForTable returns the columns in a table

func (*Conn) Count

func (c *Conn) Count(schema, table string) int64

Count returns a count of rows in a table, returns -1 on error

func (*Conn) Counter added in v1.0.51

func (c *Conn) Counter() int64

Counter returns unique connection counter

func (*Conn) Detach added in v1.0.51

func (conn *Conn) Detach(schema string) error

Detach database

func (*Conn) Do

func (conn *Conn) Do(ctx context.Context, flag SQFlag, fn func(SQTransaction) error) error

Perform a transaction, rollback if error is returned

func (*Conn) Exec

func (conn *Conn) Exec(st SQStatement, fn SQExecFunc) error

Execute SQL statement without preparing, and invoke a callback for each row of results which may return true to abort

func (*Conn) Filename

func (c *Conn) Filename(schema string) string

Filename returns the filename for a schema

func (*Conn) Flags

func (c *Conn) Flags() SQFlag

Flags returns the Open Flags

func (*Conn) ForeignKeyConstraints

func (this *Conn) ForeignKeyConstraints() (bool, error)

func (*Conn) IndexesForTable

func (c *Conn) IndexesForTable(schema, table string) []SQIndexView

IndexesForTable returns the indexes associated with a table

func (*Conn) Modules

func (c *Conn) Modules(prefix ...string) []string

Modules returns a list of modules in a schema. If an argument is provided, then only modules with those name prefixes are returned.

func (*Conn) Query

func (conn *Conn) Query(st SQStatement, v ...interface{}) (SQResults, error)

Execute SQL statement outside of transaction - currently not implemented

func (*Conn) Schemas

func (c *Conn) Schemas() []string

Schemas returns a list of schemas

func (*Conn) SetForeignKeyConstraints

func (this *Conn) SetForeignKeyConstraints(enable bool) error

func (*Conn) SetTraceHook

func (c *Conn) SetTraceHook(fn TraceFunc)

SetTraceHook sets a function to receive executed SQL statements, with the time it took to execute them. The callback is provided with the SQL statement. If the second argument is less than zero, the callback is preparing a statement for execution. If the second argument is non-zero, the callback is invoked when the statement is completed.

func (*Conn) String added in v1.0.51

func (conn *Conn) String() string

func (*Conn) Tables

func (c *Conn) Tables(schema string) []string

Tables returns a list of table names in a schema

func (*Conn) Views

func (c *Conn) Views(schema string) []string

Views returns a list of view names in a schema

type ConnCache

type ConnCache struct {
	sync.Mutex
	sync.Map
	// contains filtered or unexported fields
}

func (*ConnCache) Close

func (cache *ConnCache) Close() error

Close all conn cache prepared statements

func (*ConnCache) Prepare

func (cache *ConnCache) Prepare(conn *sqlite3.ConnEx, q string) (*Results, error)

Return a prepared statement from the cache, or prepare a new statement and put it in the cache before returning

func (*ConnCache) SetCap

func (cache *ConnCache) SetCap(cap uint32)

func (*ConnCache) String added in v1.0.51

func (cache *ConnCache) String() string

type ExecFunc

type ExecFunc sqlite3.ExecFunc

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool is a connection pool object

func NewPool

func NewPool(path string, errs chan<- error) (*Pool, error)

NewPool returns a new default pool with a shared cache and maxiumum pool size of 5 connections. If filename is not empty, this database is opened or else memory is used. Pass a channel to receive errors, or nil to ignore

func OpenPool

func OpenPool(config PoolConfig, errs chan<- error) (*Pool, error)

OpenPool returns a new pool with the specified configuration

func (*Pool) Close

func (p *Pool) Close() error

Close waits for all connections to be released and then releases resources

func (*Pool) Cur

func (p *Pool) Cur() int

Return number of "checked out" (used) connections

func (*Pool) Get

func (p *Pool) Get() SQConnection

func (*Pool) Max added in v1.0.37

func (p *Pool) Max() int

Return maximum allowed connections

func (*Pool) Put

func (p *Pool) Put(conn SQConnection)

func (*Pool) SetMax

func (p *Pool) SetMax(n int)

Set maximum number of "checked out" connections

func (*Pool) String

func (p *Pool) String() string

type PoolConfig

type PoolConfig struct {
	Max     int32             `yaml:"max"`       // The maximum number of connections in the pool
	Schemas map[string]string `yaml:"databases"` // Schema names mapped onto path for database file
	Create  bool              `yaml:"create"`    // When false, do not allow creation of new file-based databases
	Auth    SQAuth            // Authentication and Authorization interface
	Trace   TraceFunc         // Trace function
	Flags   SQFlag            // Flags for opening connections
}

PoolConfig is the starting configuration for a pool

func NewConfig

func NewConfig() PoolConfig

Create a new default configuraiton for the pool

func (PoolConfig) WithAuth

func (cfg PoolConfig) WithAuth(auth SQAuth) PoolConfig

Enable authentication and authorization

func (PoolConfig) WithCreate added in v1.0.37

func (cfg PoolConfig) WithCreate(create bool) PoolConfig

Enable or disable creation of database files

func (PoolConfig) WithMaxConnections

func (cfg PoolConfig) WithMaxConnections(n int) PoolConfig

Set maxmimum concurrent connections

func (PoolConfig) WithSchema

func (cfg PoolConfig) WithSchema(name, path string) PoolConfig

Add schema to the pool

func (PoolConfig) WithTrace

func (cfg PoolConfig) WithTrace(fn TraceFunc) PoolConfig

Enable trace of statement execution

type Results

type Results struct {
	// contains filtered or unexported fields
}

PoolConfig is the starting configuration for a pool

func NewResults

func NewResults(st *sqlite3.StatementEx) *Results

func (*Results) Close added in v1.0.48

func (r *Results) Close() error

func (*Results) ColumnSource

func (r *Results) ColumnSource(i int) (string, string, string)

func (*Results) Columns

func (r *Results) Columns() []SQColumn

Return the columns for the current results

func (*Results) ExpandedSQL

func (r *Results) ExpandedSQL() string

func (*Results) LastInsertId

func (r *Results) LastInsertId() int64

Return LastInsertId by last execute or -1 if no valid results

func (*Results) Next

func (r *Results) Next(t ...reflect.Type) []interface{}

Return a row from the results, or return io.EOF if all results have been consumed

func (*Results) NextQuery

func (r *Results) NextQuery(v ...interface{}) error

NextQuery will execute the next query in the statement, return io.EOF if there are no more statements. In order to read the rows, repeatedly read the rows using the Next function.

func (*Results) RowsAffected

func (r *Results) RowsAffected() int

Return RowsAffected by last execute or -1 if no valid results

func (*Results) String

func (r *Results) String() string

type TraceFunc

type TraceFunc func(c *Conn, q string, delta time.Duration)

TraceFunc is a function that is called when a statement is executed or prepared

type Txn

type Txn struct {
	sync.Mutex
	*Conn
	// contains filtered or unexported fields
}

func (*Txn) Flags

func (t *Txn) Flags() SQFlag

Flags returns the Open Flags or'd with Transaction Flags

func (*Txn) Query

func (txn *Txn) Query(st SQStatement, v ...interface{}) (SQResults, error)

Execute SQL statement and invoke a callback for each row of results which may return true to abort

type TxnFunc

type TxnFunc func(SQTransaction) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL