@@ -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
6564It's possible to create custom functions (both in a scalar and aggregate context)
6665and use perform streaming read and write operations on large binary (BLOB) objects.
@@ -72,38 +71,223 @@ method:
7271package main
7372
7473import (
75- sqlite " github.com/mutablelogic/go-sqlite/pkg/sqlite3"
74+ sqlite3 " github.com/mutablelogic/go-sqlite/pkg/sqlite3"
7675)
7776
7877func 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
9695In this example, a database is opened and the ` Get ` method obtains a connection
9796to 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
0 commit comments