@@ -451,15 +451,14 @@ type SQLiteConn struct {
451451 txlock string
452452 funcs []* functionInfo
453453 aggregators []* aggInfo
454- // Prepared-statement cache. stmtCacheBuf is a preallocated slice of
455- // length stmtCacheSize holding up to stmtCacheCount live entries at
456- // indices [0, stmtCacheCount). Ordering is LRU-first: index 0 is the
457- // oldest (next to be evicted), index stmtCacheCount-1 is the most
458- // recently put. put at the tail is O(1) when not full; eviction shifts
459- // the remaining entries left by one.
460- stmtCacheBuf []* SQLiteStmt
461- stmtCacheSize int
462- stmtCacheCount int
454+ // Prepared-statement cache. The slice is allocated at Open with a
455+ // fixed capacity equal to the configured cache size; cap bounds the
456+ // cache, len is the live count, and entries are ordered LRU-first
457+ // (index 0 is the oldest, the tail is most recently put). Access
458+ // requires mu; stmtCacheEnabled is immutable after Open and is the
459+ // only field safe to read without the lock.
460+ stmtCache []* SQLiteStmt
461+ stmtCacheEnabled bool
463462}
464463
465464// SQLiteTx implements driver.Tx.
@@ -1617,9 +1616,10 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
16171616 //
16181617
16191618 // Create connection to SQLite
1620- conn := & SQLiteConn {db : db , loc : loc , txlock : txlock , stmtCacheSize : stmtCacheSize }
1619+ conn := & SQLiteConn {db : db , loc : loc , txlock : txlock }
16211620 if stmtCacheSize > 0 {
1622- conn .stmtCacheBuf = make ([]* SQLiteStmt , stmtCacheSize )
1621+ conn .stmtCache = make ([]* SQLiteStmt , 0 , stmtCacheSize )
1622+ conn .stmtCacheEnabled = true
16231623 }
16241624
16251625 // Password Cipher has to be registered before authentication
@@ -1913,7 +1913,7 @@ func (c *SQLiteConn) dbConnOpen() bool {
19131913}
19141914
19151915func (c * SQLiteConn ) takeCachedStmt (query string ) * SQLiteStmt {
1916- if c == nil || query == "" || c . stmtCacheSize <= 0 {
1916+ if c == nil || query == "" || ! c . stmtCacheEnabled {
19171917 return nil
19181918 }
19191919
@@ -1925,17 +1925,15 @@ func (c *SQLiteConn) takeCachedStmt(query string) *SQLiteStmt {
19251925 }
19261926 // Scan from the MRU end (tail) so that a stmt put just before is
19271927 // found immediately.
1928- for i := c . stmtCacheCount - 1 ; i >= 0 ; i -- {
1929- s := c .stmtCacheBuf [i ]
1928+ for i := len ( c . stmtCache ) - 1 ; i >= 0 ; i -- {
1929+ s := c .stmtCache [i ]
19301930 if s .cacheKey != query {
19311931 continue
19321932 }
1933- // Remove s from the buffer by shifting subsequent entries left.
1934- if i != c .stmtCacheCount - 1 {
1935- copy (c .stmtCacheBuf [i :c .stmtCacheCount - 1 ], c .stmtCacheBuf [i + 1 :c .stmtCacheCount ])
1936- }
1937- c .stmtCacheCount --
1938- c .stmtCacheBuf [c .stmtCacheCount ] = nil
1933+ n := len (c .stmtCache )
1934+ copy (c .stmtCache [i :n - 1 ], c .stmtCache [i + 1 :n ])
1935+ c .stmtCache [n - 1 ] = nil
1936+ c .stmtCache = c .stmtCache [:n - 1 ]
19391937 s .closed = false
19401938 s .cls = false
19411939 s .t = ""
@@ -1945,7 +1943,7 @@ func (c *SQLiteConn) takeCachedStmt(query string) *SQLiteStmt {
19451943}
19461944
19471945func (c * SQLiteConn ) putCachedStmt (s * SQLiteStmt ) bool {
1948- if c == nil || s == nil || s .s == nil || s .cacheKey == "" || c . stmtCacheSize <= 0 {
1946+ if c == nil || s == nil || s .s == nil || s .cacheKey == "" || ! c . stmtCacheEnabled {
19491947 return false
19501948 }
19511949
@@ -1959,30 +1957,27 @@ func (c *SQLiteConn) putCachedStmt(s *SQLiteStmt) bool {
19591957 if rv != C .SQLITE_ROW && rv != C .SQLITE_OK && rv != C .SQLITE_DONE {
19601958 return false
19611959 }
1962- // If full, finalize the least-recently-used entry at index 0 and
1963- // compact the remaining entries left by one .
1964- if c . stmtCacheCount == c . stmtCacheSize {
1965- victim := c .stmtCacheBuf [0 ]
1960+ // If full, finalize the LRU entry at index 0 and shift left; the
1961+ // freed tail slot is immediately reused by the append below .
1962+ if len ( c . stmtCache ) == cap ( c . stmtCache ) {
1963+ victim := c .stmtCache [0 ]
19661964 runtime .SetFinalizer (victim , nil )
19671965 if victim .s != nil {
19681966 C .sqlite3_finalize (victim .s )
19691967 victim .s = nil
19701968 }
19711969 victim .c = nil
19721970 victim .closed = true
1973- copy (c .stmtCacheBuf [ 0 : c . stmtCacheCount - 1 ] , c .stmtCacheBuf [1 :c . stmtCacheCount ])
1974- c .stmtCacheCount --
1971+ copy (c .stmtCache , c .stmtCache [1 :])
1972+ c .stmtCache = c . stmtCache [: len ( c . stmtCache ) - 1 ]
19751973 }
1976- // Append at the MRU tail.
1977- c .stmtCacheBuf [c .stmtCacheCount ] = s
1978- c .stmtCacheCount ++
1974+ c .stmtCache = append (c .stmtCache , s )
19791975 return true
19801976}
19811977
19821978func (c * SQLiteConn ) closeCachedStmtsLocked () {
1983- for i := 0 ; i < c .stmtCacheCount ; i ++ {
1984- s := c .stmtCacheBuf [i ]
1985- c .stmtCacheBuf [i ] = nil
1979+ for i , s := range c .stmtCache {
1980+ c .stmtCache [i ] = nil
19861981 if s == nil || s .s == nil {
19871982 continue
19881983 }
@@ -1991,7 +1986,7 @@ func (c *SQLiteConn) closeCachedStmtsLocked() {
19911986 s .s = nil
19921987 s .c = nil
19931988 }
1994- c .stmtCacheCount = 0
1989+ c .stmtCache = c . stmtCache [: 0 ]
19951990}
19961991
19971992// Prepare the query string. Return a new statement.
0 commit comments