summaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgx/v5/internal/stmtcache
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jackc/pgx/v5/internal/stmtcache')
-rw-r--r--vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go98
-rw-r--r--vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go57
-rw-r--r--vendor/github.com/jackc/pgx/v5/internal/stmtcache/unlimited_cache.go71
3 files changed, 226 insertions, 0 deletions
diff --git a/vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go
new file mode 100644
index 000000000..a25cc8b1c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/lru_cache.go
@@ -0,0 +1,98 @@
+package stmtcache
+
+import (
+ "container/list"
+
+ "github.com/jackc/pgx/v5/pgconn"
+)
+
+// LRUCache implements Cache with a Least Recently Used (LRU) cache.
+type LRUCache struct {
+ cap int
+ m map[string]*list.Element
+ l *list.List
+ invalidStmts []*pgconn.StatementDescription
+}
+
+// NewLRUCache creates a new LRUCache. cap is the maximum size of the cache.
+func NewLRUCache(cap int) *LRUCache {
+ return &LRUCache{
+ cap: cap,
+ m: make(map[string]*list.Element),
+ l: list.New(),
+ }
+}
+
+// Get returns the statement description for sql. Returns nil if not found.
+func (c *LRUCache) Get(key string) *pgconn.StatementDescription {
+ if el, ok := c.m[key]; ok {
+ c.l.MoveToFront(el)
+ return el.Value.(*pgconn.StatementDescription)
+ }
+
+ return nil
+
+}
+
+// Put stores sd in the cache. Put panics if sd.SQL is "". Put does nothing if sd.SQL already exists in the cache.
+func (c *LRUCache) Put(sd *pgconn.StatementDescription) {
+ if sd.SQL == "" {
+ panic("cannot store statement description with empty SQL")
+ }
+
+ if _, present := c.m[sd.SQL]; present {
+ return
+ }
+
+ if c.l.Len() == c.cap {
+ c.invalidateOldest()
+ }
+
+ el := c.l.PushFront(sd)
+ c.m[sd.SQL] = el
+}
+
+// Invalidate invalidates statement description identified by sql. Does nothing if not found.
+func (c *LRUCache) Invalidate(sql string) {
+ if el, ok := c.m[sql]; ok {
+ delete(c.m, sql)
+ c.invalidStmts = append(c.invalidStmts, el.Value.(*pgconn.StatementDescription))
+ c.l.Remove(el)
+ }
+}
+
+// InvalidateAll invalidates all statement descriptions.
+func (c *LRUCache) InvalidateAll() {
+ el := c.l.Front()
+ for el != nil {
+ c.invalidStmts = append(c.invalidStmts, el.Value.(*pgconn.StatementDescription))
+ el = el.Next()
+ }
+
+ c.m = make(map[string]*list.Element)
+ c.l = list.New()
+}
+
+func (c *LRUCache) HandleInvalidated() []*pgconn.StatementDescription {
+ invalidStmts := c.invalidStmts
+ c.invalidStmts = nil
+ return invalidStmts
+}
+
+// Len returns the number of cached prepared statement descriptions.
+func (c *LRUCache) Len() int {
+ return c.l.Len()
+}
+
+// Cap returns the maximum number of cached prepared statement descriptions.
+func (c *LRUCache) Cap() int {
+ return c.cap
+}
+
+func (c *LRUCache) invalidateOldest() {
+ oldest := c.l.Back()
+ sd := oldest.Value.(*pgconn.StatementDescription)
+ c.invalidStmts = append(c.invalidStmts, sd)
+ delete(c.m, sd.SQL)
+ c.l.Remove(oldest)
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go
new file mode 100644
index 000000000..e1bdcba57
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/stmtcache.go
@@ -0,0 +1,57 @@
+// Package stmtcache is a cache for statement descriptions.
+package stmtcache
+
+import (
+ "strconv"
+ "sync/atomic"
+
+ "github.com/jackc/pgx/v5/pgconn"
+)
+
+var stmtCounter int64
+
+// NextStatementName returns a statement name that will be unique for the lifetime of the program.
+func NextStatementName() string {
+ n := atomic.AddInt64(&stmtCounter, 1)
+ return "stmtcache_" + strconv.FormatInt(n, 10)
+}
+
+// Cache caches statement descriptions.
+type Cache interface {
+ // Get returns the statement description for sql. Returns nil if not found.
+ Get(sql string) *pgconn.StatementDescription
+
+ // Put stores sd in the cache. Put panics if sd.SQL is "". Put does nothing if sd.SQL already exists in the cache.
+ Put(sd *pgconn.StatementDescription)
+
+ // Invalidate invalidates statement description identified by sql. Does nothing if not found.
+ Invalidate(sql string)
+
+ // InvalidateAll invalidates all statement descriptions.
+ InvalidateAll()
+
+ // HandleInvalidated returns a slice of all statement descriptions invalidated since the last call to HandleInvalidated.
+ HandleInvalidated() []*pgconn.StatementDescription
+
+ // Len returns the number of cached prepared statement descriptions.
+ Len() int
+
+ // Cap returns the maximum number of cached prepared statement descriptions.
+ Cap() int
+}
+
+func IsStatementInvalid(err error) bool {
+ pgErr, ok := err.(*pgconn.PgError)
+ if !ok {
+ return false
+ }
+
+ // https://github.com/jackc/pgx/issues/1162
+ //
+ // We used to look for the message "cached plan must not change result type". However, that message can be localized.
+ // Unfortunately, error code "0A000" - "FEATURE NOT SUPPORTED" is used for many different errors and the only way to
+ // tell the difference is by the message. But all that happens is we clear a statement that we otherwise wouldn't
+ // have so it should be safe.
+ possibleInvalidCachedPlanError := pgErr.Code == "0A000"
+ return possibleInvalidCachedPlanError
+}
diff --git a/vendor/github.com/jackc/pgx/v5/internal/stmtcache/unlimited_cache.go b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/unlimited_cache.go
new file mode 100644
index 000000000..f5f59396e
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v5/internal/stmtcache/unlimited_cache.go
@@ -0,0 +1,71 @@
+package stmtcache
+
+import (
+ "math"
+
+ "github.com/jackc/pgx/v5/pgconn"
+)
+
+// UnlimitedCache implements Cache with no capacity limit.
+type UnlimitedCache struct {
+ m map[string]*pgconn.StatementDescription
+ invalidStmts []*pgconn.StatementDescription
+}
+
+// NewUnlimitedCache creates a new UnlimitedCache.
+func NewUnlimitedCache() *UnlimitedCache {
+ return &UnlimitedCache{
+ m: make(map[string]*pgconn.StatementDescription),
+ }
+}
+
+// Get returns the statement description for sql. Returns nil if not found.
+func (c *UnlimitedCache) Get(sql string) *pgconn.StatementDescription {
+ return c.m[sql]
+}
+
+// Put stores sd in the cache. Put panics if sd.SQL is "". Put does nothing if sd.SQL already exists in the cache.
+func (c *UnlimitedCache) Put(sd *pgconn.StatementDescription) {
+ if sd.SQL == "" {
+ panic("cannot store statement description with empty SQL")
+ }
+
+ if _, present := c.m[sd.SQL]; present {
+ return
+ }
+
+ c.m[sd.SQL] = sd
+}
+
+// Invalidate invalidates statement description identified by sql. Does nothing if not found.
+func (c *UnlimitedCache) Invalidate(sql string) {
+ if sd, ok := c.m[sql]; ok {
+ delete(c.m, sql)
+ c.invalidStmts = append(c.invalidStmts, sd)
+ }
+}
+
+// InvalidateAll invalidates all statement descriptions.
+func (c *UnlimitedCache) InvalidateAll() {
+ for _, sd := range c.m {
+ c.invalidStmts = append(c.invalidStmts, sd)
+ }
+
+ c.m = make(map[string]*pgconn.StatementDescription)
+}
+
+func (c *UnlimitedCache) HandleInvalidated() []*pgconn.StatementDescription {
+ invalidStmts := c.invalidStmts
+ c.invalidStmts = nil
+ return invalidStmts
+}
+
+// Len returns the number of cached prepared statement descriptions.
+func (c *UnlimitedCache) Len() int {
+ return len(c.m)
+}
+
+// Cap returns the maximum number of cached prepared statement descriptions.
+func (c *UnlimitedCache) Cap() int {
+ return math.MaxInt
+}