Skip to content

Commit 9432a3b

Browse files
committed
Updated
1 parent d81573c commit 9432a3b

File tree

2 files changed

+210
-45
lines changed

2 files changed

+210
-45
lines changed

pkg/sqlite3/README.md

Lines changed: 209 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ The package includes:
5959
* A Connection __Pool__ for managing connections to sqlite3 databases;
6060
* A __Connection__ for executing queries;
6161
* An __Auth__ interface for managing authentication and authorization;
62-
* A __Cache__ for managing prepared statements and profiling for slow
63-
queries.
62+
* A __Cache__ for managing prepared statements.
6463

6564
It's possible to create custom functions (both in a scalar and aggregate context)
6665
and use perform streaming read and write operations on large binary (BLOB) objects.
@@ -72,38 +71,223 @@ method:
7271
package main
7372

7473
import (
75-
sqlite "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
74+
sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
7675
)
7776

7877
func main() {
79-
pool, err := sqlite.NewPool(path, nil)
80-
if err != nil {
81-
panic(err)
82-
}
83-
defer pool.Close()
78+
pool, err := sqlite3.NewPool(path, nil)
79+
if err != nil {
80+
panic(err)
81+
}
82+
defer pool.Close()
8483

85-
// Onbtain a connection from pool, put back when done
86-
conn := pool.Get(context.Background())
87-
defer pool.Put(conn)
84+
// Onbtain a connection from pool, put back when done
85+
conn := pool.Get()
86+
defer pool.Put(conn)
8887

89-
// Enumerate the tables in the database
90-
tables := conn.Tables()
88+
// Enumerate the tables in the database
89+
tables := conn.Tables()
9190

92-
// ...
91+
// ...
9392
}
9493
```
9594

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

100100
## Connection Pool
101101

102-
TODO
102+
A __Pool__ is a common pattern for managing connections to a database, where there
103+
is a limited number of connections available with concurrent accesses to the database.
104+
The pool can be created in two ways:
105+
106+
1. `sqlite3.NewPool(path string, errs chan<- error) (*Pool, error)` creates a standard pool
107+
for a single database (referred to by file path or as `:memory:` for an in-memory database);
108+
2. `sqlite3.OpenPool(config sqlite3.PoolConfig, errs chan<- error) (*Pool, error) ` creates
109+
a pool with a configuration; more information on the configuration can be found below.
110+
111+
In either case, the second argument can be `nil` or a channel for receiving errors. Errors are
112+
received in this way so that the pool method `Get` can return `nil` if an error occurs, but
113+
errors can still be reported for debugging.
114+
115+
### Pool Configuration
116+
117+
By default the pool will create a maximum of 5 simultaneous connections to the database.
118+
However, you can use the `NewConfig()` method with options to alter the default configuration.
119+
For example,
120+
121+
122+
```go
123+
package main
124+
125+
import (
126+
sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
127+
)
128+
129+
func main() {
130+
cfg := sqlite3.NewConfig().SetMaxConnections(100)
131+
pool, err := sqlite3.OpenPool(cfg, nil)
132+
if err != nil {
133+
panic(err)
134+
}
135+
defer pool.Close()
136+
137+
// ...
138+
}
139+
```
140+
141+
The different options to modify the default configuration are:
142+
143+
* `func (PoolConfig) WithAuth(SQAuth)` sets the authentication and authorization
144+
interface for any executed statements. More information about this interface can
145+
be found in the section below.
146+
* `func (PoolConfig) WithTrace(TraceFunc)` sets a trace function for the pool, so that
147+
you can monitor the activity executing statements. More information about this
148+
can be found in the section below.
149+
* `func (PoolConfig) WithMaxConnections(int)` sets the maximum number of connections
150+
to the database. Setting a value of `0` will use the default number of connections.
151+
* `func (PoolConfig) WithSchema(name, path string)` adds a database schema to the
152+
connection pool. One schema should always be named `main`. Setting the path argument
153+
to `:memory:` will set the schema to an in-memory database, otherwise the schema will
154+
be read from disk.
155+
156+
### Getting a Connection
157+
158+
Once you have created a pool, you can obtain a connection from the pool using the `Get` method,
159+
which should always be paired with a `Put` call:
160+
161+
```go
162+
package main
163+
164+
import (
165+
sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
166+
)
167+
168+
func main() {
169+
pool, err := sqlite3.NewPool(":memory:", nil)
170+
if err != nil {
171+
panic(err)
172+
}
173+
defer pool.Close()
174+
175+
// Get connection
176+
conn := pool.Get()
177+
if conn == nil {
178+
panic("No connection")
179+
}
180+
defer pool.Put(conn)
181+
182+
// ...
183+
}
184+
```
185+
186+
The `Get` method may return nil if the maximum number of connections has been reached.
187+
Once a connection has been `Put` back into the pool, it should no longer be used (there
188+
is nothing presently to prevent use of a connection after it has been `Put` back, but
189+
it could be added in later).
190+
191+
### Example code for reporting errors
192+
193+
In general you should pass a channel for receiving errors. Here is some sample code
194+
you can use for doing this:
195+
196+
```go
197+
func createErrorChannel() (chan<- error, context.CancelFunc) {
198+
var wg sync.WaitGroup
199+
errs := make(chan error)
200+
ctx, cancel := context.WithCancel(context.Background())
201+
wg.Add(1)
202+
go func() {
203+
defer wg.Done()
204+
for {
205+
select {
206+
case <-ctx.Done():
207+
close(errs)
208+
return
209+
case err := <-errs:
210+
if err != nil {
211+
// Replace the following line
212+
log.Print(err)
213+
}
214+
}
215+
}
216+
}()
217+
218+
return errs, func() { cancel(); wg.Wait() }
219+
}
220+
```
221+
222+
The function will return the error channel and a cancel function. The cancel function
223+
should only be called after the pool has been closed to ensure that the pool does not
224+
try and report errors to a closed error channel.
103225

104226
## Transactions and Queries
105227

106-
TODO
228+
There are two connection methods for executing queries:
229+
230+
### Execution outside a transaction
231+
232+
The function `func (SQConnection) Exec(SQStatement, SQExecFunc) error` executes a
233+
callback function with the result of the query. For example,
234+
235+
```go
236+
package main
237+
238+
import (
239+
sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
240+
. "github.com/mutablelogic/go-sqlite/pkg/sqlang"
241+
)
242+
243+
func main() {
244+
// ...
245+
conn.Exec(Q("PRAGMA module_list"), func(row, cols []string) bool {
246+
fmt.Println(row)
247+
return false
248+
})
249+
}
250+
```
251+
252+
Use this method to run statements which don't need committing or rolling back
253+
on errors, or which only need text information returned.
254+
255+
### Execution in a transaction
256+
257+
On the whole you will want to operate the database inside tansactions. In order
258+
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
259+
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.
260+
261+
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:
262+
263+
* `SQLITE_TXN_DEFAULT` Default (deferred) transaction flag (can be omitted if not needed)
264+
* `SQLITE_TXN_IMMEDIATE` Immediate transaction
265+
* `SQLITE_TXN_EXCLUSIVE` Exclusive transaction
266+
* `SQLITE_TXN_NO_FOREIGNKEY_CONSTRAINTS` Drop foreign key constraints within the transaction
267+
268+
More information about different types of transactions is documented [here](https://www.sqlite.org/lang_transaction.html).
269+
270+
For example,
271+
272+
```go
273+
package main
274+
275+
import (
276+
sqlite3 "github.com/mutablelogic/go-sqlite/pkg/sqlite3"
277+
. "github.com/mutablelogic/go-sqlite/pkg/sqlang"
278+
)
279+
280+
func main() {
281+
// ...
282+
conn.Do(context.Background(),0,func(txn SQTransaction) error {
283+
if _, err := txn.Query(N("test").Insert().WithDefaultValues()); err != nil {
284+
return err
285+
}
286+
// Commit transaction
287+
return nil
288+
})
289+
}
290+
```
107291

108292
## Custom Types
109293

@@ -119,9 +303,16 @@ TODO
119303

120304
## Pool Status
121305

122-
TODO
306+
There are two methods which can be used for getting and setting pool status:
307+
308+
* `func (SQPool) Cur() int` returns the current number of connections in the pool;
309+
* `func (SQPool) SetMax(n int)` sets the maximum number of connections allowed in the pool.
310+
This will not affect the number of connections currently in the pool, however.
123311

124312
## Reading and Writing Large Objects
125313

314+
TODO
315+
126316
## Backup
127317

318+
TODO

sqlite.go

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const (
1717
type (
1818
SQAuthFlag uint32
1919
SQFlag uint32
20+
SQTxnFunc func(SQTransaction) error
2021
SQExecFunc func(row, col []string) bool
2122
)
2223

@@ -41,10 +42,6 @@ type SQPool interface {
4142
// SetMax allowed connections released from pool. Note this does not change
4243
// the maximum instantly, it will settle to this value over time.
4344
SetMax(int)
44-
45-
// SlowQueries returns the slowest N queries if tracing is switched on, returns
46-
// nil if no tracing has been turned on
47-
//SlowQueries(n int) []SQSlowQuery
4845
}
4946

5047
// SQConnection is an sqlite connection to one or more databases
@@ -140,29 +137,6 @@ type SQAuth interface {
140137
CanExec(context.Context, SQAuthFlag, string, ...string) error
141138
}
142139

143-
/*
144-
// SQSlowQuery returns a profile for a query
145-
type SQSlowQuery interface {
146-
// Return the query text
147-
SQL() string
148-
149-
// Return the minimum query time
150-
Min() time.Duration
151-
152-
// Return the maximum query time
153-
Max() time.Duration
154-
155-
// Return the mean average query time
156-
Mean() time.Duration
157-
158-
// Return the number of samples
159-
Count() int
160-
161-
// Return the period over which the samples were taken
162-
Delta() time.Duration
163-
}
164-
*/
165-
166140
///////////////////////////////////////////////////////////////////////////////
167141
// GLOBALS
168142

0 commit comments

Comments
 (0)