@@ -445,12 +445,15 @@ type SQLiteDriver struct {
445445
446446// SQLiteConn implements driver.Conn.
447447type SQLiteConn struct {
448- mu sync.Mutex
449- db * C.sqlite3
450- loc * time.Location
451- txlock string
452- funcs []* functionInfo
453- aggregators []* aggInfo
448+ mu sync.Mutex
449+ db * C.sqlite3
450+ loc * time.Location
451+ txlock string
452+ funcs []* functionInfo
453+ aggregators []* aggInfo
454+ stmtCache map [string ][]* SQLiteStmt
455+ stmtCacheSize int
456+ stmtCacheCount int
454457}
455458
456459// SQLiteTx implements driver.Tx.
@@ -467,6 +470,7 @@ type SQLiteStmt struct {
467470 closed bool
468471 cls bool // True if the statement was created by SQLiteConn.Query
469472 namedParams map [string ][3 ]int
473+ cacheKey string
470474}
471475
472476// SQLiteResult implements sql.Result.
@@ -944,7 +948,7 @@ func (c *SQLiteConn) exec(ctx context.Context, query string, args []driver.Named
944948
945949 start := 0
946950 for {
947- s , err := c .prepare (ctx , query )
951+ s , err := c .prepareWithCache (ctx , query , true )
948952 if err != nil {
949953 return nil , err
950954 }
@@ -1009,7 +1013,7 @@ func (c *SQLiteConn) Query(query string, args []driver.Value) (driver.Rows, erro
10091013func (c * SQLiteConn ) query (ctx context.Context , query string , args []driver.NamedValue ) (driver.Rows , error ) {
10101014 start := 0
10111015 for {
1012- s , err := c .prepare (ctx , query )
1016+ s , err := c .prepareWithCache (ctx , query , true )
10131017 if err != nil {
10141018 return nil , err
10151019 }
@@ -1185,6 +1189,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
11851189 writableSchema := - 1
11861190 vfsName := ""
11871191 var cacheSize * int64
1192+ stmtCacheSize := 0
11881193
11891194 pos := strings .IndexRune (dsn , '?' )
11901195 if pos >= 1 {
@@ -1520,6 +1525,17 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
15201525 cacheSize = & iv
15211526 }
15221527
1528+ if val := params .Get ("_stmt_cache_size" ); val != "" {
1529+ iv , err := strconv .Atoi (val )
1530+ if err != nil {
1531+ return nil , fmt .Errorf ("Invalid _stmt_cache_size: %v: %v" , val , err )
1532+ }
1533+ if iv < 0 {
1534+ return nil , fmt .Errorf ("Invalid _stmt_cache_size: %v, expecting non-negative integer" , val )
1535+ }
1536+ stmtCacheSize = iv
1537+ }
1538+
15231539 if val := params .Get ("vfs" ); val != "" {
15241540 vfsName = val
15251541 }
@@ -1592,7 +1608,10 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
15921608 //
15931609
15941610 // Create connection to SQLite
1595- conn := & SQLiteConn {db : db , loc : loc , txlock : txlock }
1611+ conn := & SQLiteConn {db : db , loc : loc , txlock : txlock , stmtCacheSize : stmtCacheSize }
1612+ if stmtCacheSize > 0 {
1613+ conn .stmtCache = make (map [string ][]* SQLiteStmt )
1614+ }
15961615
15971616 // Password Cipher has to be registered before authentication
15981617 if len (authCrypt ) > 0 {
@@ -1865,6 +1884,9 @@ func (c *SQLiteConn) Close() error {
18651884 return nil
18661885 }
18671886 runtime .SetFinalizer (c , nil )
1887+ if err := c .closeCachedStmtsLocked (); err != nil {
1888+ return err
1889+ }
18681890 rv := C .sqlite3_close_v2 (c .db )
18691891 if rv != C .SQLITE_OK {
18701892 return lastError (c .db )
@@ -1883,12 +1905,85 @@ func (c *SQLiteConn) dbConnOpen() bool {
18831905 return c .db != nil
18841906}
18851907
1908+ func (c * SQLiteConn ) takeCachedStmt (query string ) * SQLiteStmt {
1909+ if c == nil || query == "" {
1910+ return nil
1911+ }
1912+
1913+ c .mu .Lock ()
1914+ defer c .mu .Unlock ()
1915+
1916+ if c .db == nil || c .stmtCacheSize <= 0 {
1917+ return nil
1918+ }
1919+ stmts := c .stmtCache [query ]
1920+ if len (stmts ) == 0 {
1921+ return nil
1922+ }
1923+ s := stmts [len (stmts )- 1 ]
1924+ if len (stmts ) == 1 {
1925+ delete (c .stmtCache , query )
1926+ } else {
1927+ c .stmtCache [query ] = stmts [:len (stmts )- 1 ]
1928+ }
1929+ c .stmtCacheCount --
1930+ s .closed = false
1931+ s .cls = false
1932+ s .t = ""
1933+ return s
1934+ }
1935+
1936+ func (c * SQLiteConn ) putCachedStmt (s * SQLiteStmt ) bool {
1937+ if c == nil || s == nil || s .s == nil || s .cacheKey == "" {
1938+ return false
1939+ }
1940+
1941+ c .mu .Lock ()
1942+ defer c .mu .Unlock ()
1943+
1944+ if c .db == nil || c .stmtCacheSize <= 0 || c .stmtCacheCount >= c .stmtCacheSize {
1945+ return false
1946+ }
1947+ c .stmtCache [s .cacheKey ] = append (c .stmtCache [s .cacheKey ], s )
1948+ c .stmtCacheCount ++
1949+ return true
1950+ }
1951+
1952+ func (c * SQLiteConn ) closeCachedStmtsLocked () error {
1953+ for key , stmts := range c .stmtCache {
1954+ for _ , s := range stmts {
1955+ if s == nil || s .s == nil {
1956+ continue
1957+ }
1958+ runtime .SetFinalizer (s , nil )
1959+ if rv := C .sqlite3_finalize (s .s ); rv != C .SQLITE_OK {
1960+ return lastError (c .db )
1961+ }
1962+ s .s = nil
1963+ s .c = nil
1964+ }
1965+ delete (c .stmtCache , key )
1966+ }
1967+ c .stmtCacheCount = 0
1968+ return nil
1969+ }
1970+
18861971// Prepare the query string. Return a new statement.
18871972func (c * SQLiteConn ) Prepare (query string ) (driver.Stmt , error ) {
18881973 return c .prepare (context .Background (), query )
18891974}
18901975
18911976func (c * SQLiteConn ) prepare (ctx context.Context , query string ) (driver.Stmt , error ) {
1977+ return c .prepareWithCache (ctx , query , false )
1978+ }
1979+
1980+ func (c * SQLiteConn ) prepareWithCache (ctx context.Context , query string , useCache bool ) (driver.Stmt , error ) {
1981+ if useCache {
1982+ if stmt := c .takeCachedStmt (query ); stmt != nil {
1983+ return stmt , nil
1984+ }
1985+ }
1986+
18921987 pquery := C .CString (query )
18931988 defer C .free (unsafe .Pointer (pquery ))
18941989 var s * C.sqlite3_stmt
@@ -1902,6 +1997,9 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
19021997 t = strings .TrimSpace (C .GoString (tail ))
19031998 }
19041999 ss := & SQLiteStmt {c : c , s : s , t : t }
2000+ if useCache && t == "" {
2001+ ss .cacheKey = query
2002+ }
19052003 runtime .SetFinalizer (ss , (* SQLiteStmt ).Close )
19062004 return ss , nil
19072005}
@@ -2014,11 +2112,26 @@ func (s *SQLiteStmt) Close() error {
20142112 runtime .SetFinalizer (s , nil )
20152113 conn := s .c
20162114 stmt := s .s
2017- s .s = nil
2018- s .c = nil
2115+ if stmt == nil {
2116+ s .c = nil
2117+ return nil
2118+ }
20192119 if ! conn .dbConnOpen () {
20202120 return errors .New ("sqlite statement with already closed database connection" )
20212121 }
2122+ if s .cacheKey != "" {
2123+ rv := C ._sqlite3_reset_clear (stmt )
2124+ if rv != C .SQLITE_ROW && rv != C .SQLITE_OK && rv != C .SQLITE_DONE {
2125+ s .s = nil
2126+ s .c = nil
2127+ return conn .lastError ()
2128+ }
2129+ if conn .putCachedStmt (s ) {
2130+ return nil
2131+ }
2132+ }
2133+ s .s = nil
2134+ s .c = nil
20222135 rv := C .sqlite3_finalize (stmt )
20232136 if rv != C .SQLITE_OK {
20242137 return conn .lastError ()
0 commit comments