1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
// database storage
package dbstore
import (
"context"
db_sql "database/sql"
"fmt"
_ "github.com/mattn/go-sqlite3"
)
type Tx struct {
tx *db_sql.Tx // underlying transaction
sts map[string]*db_sql.Stmt // prepared statements
closed bool // are the statements closed?
done bool // is the transaction done?
err error // last error
}
func newTx(ctx context.Context, db *db_sql.DB, queryIds []string) (Tx, error) {
var r Tx
// begin context
if tx, err := db.BeginTx(ctx, nil); err != nil {
return r, err
} else {
r.tx = tx
}
// build query map
queries, err := getQueries(queryIds)
if err != nil {
return r, err
}
// build statements
sts := make(map[string]*db_sql.Stmt)
for id, sql := range(queries) {
if st, err := r.tx.PrepareContext(ctx, sql); err != nil {
return r, err
} else {
sts[id] = st
}
}
r.sts = sts
// return success
return r, nil
}
// Finalize statements.
func (tx Tx) Close() {
if !tx.closed {
for id, st := range(tx.sts) {
// close statement
st.Close()
// delete key
delete(tx.sts, id)
}
// mark transaction as closed
tx.closed = true
}
}
// Finalize statements, commit transaction.
func (tx Tx) Commit() error {
// close statements
// FIXME: this isn't really necessary, rollback and commit will take
// care of it according to the database/sql docs
tx.Close()
if !tx.done {
tx.err = tx.tx.Commit()
tx.done = true
}
// return last error
return tx.err
}
// Finalize statements, rollback transaction.
func (tx Tx) Rollback() error {
// close statements
// FIXME: this isn't really necessary, rollback and commit will take
// care of it according to the database/sql docs
tx.Close()
if !tx.done {
tx.err = tx.tx.Rollback()
tx.done = true
}
// return last error
return tx.err
}
// execute given prepared statement
func (tx Tx) Exec(ctx context.Context, id string, args... interface{}) (db_sql.Result, error) {
if st, ok := tx.sts[id]; !ok {
return nil, fmt.Errorf("unknown statement: %s", id)
} else {
return st.ExecContext(ctx, args...)
}
}
|