-
Notifications
You must be signed in to change notification settings - Fork 27
/
prepared_statement.go
93 lines (79 loc) · 2.53 KB
/
prepared_statement.go
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
package godb
import (
"database/sql"
)
// queryable represents either a Tx, a DB, or a Stmt.
type queryable interface {
Exec(args ...interface{}) (sql.Result, error)
Query(args ...interface{}) (*sql.Rows, error)
QueryRow(args ...interface{}) *sql.Row
}
// The queryWrapper type implements Queryable for sql.DB and sql.Tx
type queryWrapper struct {
db preparableAndQueryable
sqlQuery string
}
// Exec wraps the Exec method for sql.DB or sql.Tx.
func (q *queryWrapper) Exec(args ...interface{}) (sql.Result, error) {
return q.db.Exec(q.sqlQuery, args...)
}
// Query wraps the Query method for sql.DB or sql.Tx.
func (q *queryWrapper) Query(args ...interface{}) (*sql.Rows, error) {
return q.db.Query(q.sqlQuery, args...)
}
// QueryRow wraps the QueryRow method for sql.DB or sql.Tx.
func (q *queryWrapper) QueryRow(args ...interface{}) *sql.Row {
return q.db.QueryRow(q.sqlQuery, args...)
}
// getQueryable manages prepared statement, and its cache.
func (db *DB) getQueryable(query string) (queryable, error) {
return db.getQueryableWithOptions(query, false, false)
}
// getQueryableWithOptions manages prepared statement, and its cache.
// It returns a queryable interface, ignoring a possible transaction if noTx is
// true, and ignoring prepared statement cache is noStmtCache is true.
func (db *DB) getQueryableWithOptions(query string, noTx, noStmtCache bool) (queryable, error) {
// One cache for sql.DB, and one for sql.Tx
var cache *StmtCache
var dbOrTx preparableAndQueryable
if db.CurrentTx() == nil || noTx {
dbOrTx = db.sqlDB
cache = db.stmtCacheDB
} else {
dbOrTx = db.sqlTx
cache = db.stmtCacheTx
}
// If the cache is disabled, or it has not to be used, just return a wrapper
// which look like a prepared statement.
if !cache.IsEnabled() || noStmtCache {
wrapper := queryWrapper{
db: dbOrTx,
sqlQuery: query,
}
return &wrapper, nil
}
// Already prepared ?
stmt := cache.get(query)
if stmt != nil {
db.logPrintln("Use cached prepared statement")
return stmt, nil
}
// New prepared statement
db.logPrintln("Prepare statement and cache it")
stmt, err := dbOrTx.Prepare(query)
if err != nil {
return nil, err
}
cache.add(query, stmt)
return stmt, nil
}
// StmtCacheDB returns the prepared statement cache for queries outside a
// transaction (run with sql.DB).
func (db *DB) StmtCacheDB() *StmtCache {
return db.stmtCacheDB
}
// StmtCacheTx returns the prepared statement cache for queries inside a
// transaction (run with sql.Tx).
func (db *DB) StmtCacheTx() *StmtCache {
return db.stmtCacheTx
}