270 lines
5.9 KiB
Go
Raw Normal View History

package sqlruntime
import (
"sync"
"time"
)
const (
placeholderQuestion = 0
placeholderDollar = 1
fingerprintModeBasic = 0
fingerprintModeMaskLiterals = 1
)
// NormalizePlaceholderStyle converts unknown style values to default question style.
func NormalizePlaceholderStyle(style int) int {
switch style {
case placeholderDollar:
return placeholderDollar
default:
return placeholderQuestion
}
}
// NormalizeFingerprintMode converts unknown mode values to default basic mode.
func NormalizeFingerprintMode(mode int) int {
switch mode {
case fingerprintModeMaskLiterals:
return fingerprintModeMaskLiterals
default:
return fingerprintModeBasic
}
}
// State stores runtime SQL behavior toggles in a thread-safe manner.
type State struct {
mu sync.RWMutex
beforeHook interface{}
afterHook interface{}
placeholder int
slowThreshold time.Duration
fingerprintEnabled bool
fingerprintMode int
fingerprintKeepComments bool
fingerprintCounterEnabled bool
fingerprintCounts map[string]uint64
}
// Options returns snapshot of current runtime options.
func (s *State) Options() (before, after interface{}, placeholder int, slowThreshold time.Duration) {
if s == nil {
return nil, nil, placeholderQuestion, 0
}
s.mu.RLock()
before = s.beforeHook
after = s.afterHook
placeholder = NormalizePlaceholderStyle(s.placeholder)
slowThreshold = s.slowThreshold
s.mu.RUnlock()
return before, after, placeholder, slowThreshold
}
// Hooks returns before/after hooks and slow threshold.
func (s *State) Hooks() (before, after interface{}, slowThreshold time.Duration) {
before, after, _, slowThreshold = s.Options()
return before, after, slowThreshold
}
// SetHooks sets before/after hooks.
func (s *State) SetHooks(before, after interface{}) {
if s == nil {
return
}
s.mu.Lock()
s.beforeHook = before
s.afterHook = after
s.mu.Unlock()
}
// SetBeforeHook sets before hook.
func (s *State) SetBeforeHook(before interface{}) {
if s == nil {
return
}
s.mu.Lock()
s.beforeHook = before
s.mu.Unlock()
}
// SetAfterHook sets after hook.
func (s *State) SetAfterHook(after interface{}) {
if s == nil {
return
}
s.mu.Lock()
s.afterHook = after
s.mu.Unlock()
}
// SetPlaceholderStyle sets placeholder style.
func (s *State) SetPlaceholderStyle(style int) {
if s == nil {
return
}
s.mu.Lock()
s.placeholder = NormalizePlaceholderStyle(style)
s.mu.Unlock()
}
// PlaceholderStyle returns placeholder style.
func (s *State) PlaceholderStyle() int {
if s == nil {
return placeholderQuestion
}
s.mu.RLock()
style := NormalizePlaceholderStyle(s.placeholder)
s.mu.RUnlock()
return style
}
// SetSlowThreshold sets minimum duration for triggering after hook.
func (s *State) SetSlowThreshold(threshold time.Duration) {
if s == nil {
return
}
if threshold < 0 {
threshold = 0
}
s.mu.Lock()
s.slowThreshold = threshold
s.mu.Unlock()
}
// SlowThreshold returns current slow threshold.
func (s *State) SlowThreshold() time.Duration {
if s == nil {
return 0
}
s.mu.RLock()
threshold := s.slowThreshold
s.mu.RUnlock()
return threshold
}
// SetFingerprintEnabled toggles SQL fingerprint metadata generation for hooks.
func (s *State) SetFingerprintEnabled(enabled bool) {
if s == nil {
return
}
s.mu.Lock()
s.fingerprintEnabled = enabled
s.mu.Unlock()
}
// FingerprintEnabled reports whether SQL fingerprint metadata generation is enabled.
func (s *State) FingerprintEnabled() bool {
if s == nil {
return false
}
s.mu.RLock()
enabled := s.fingerprintEnabled
s.mu.RUnlock()
return enabled
}
// SetFingerprintMode sets SQL fingerprint mode.
func (s *State) SetFingerprintMode(mode int) {
if s == nil {
return
}
s.mu.Lock()
s.fingerprintMode = NormalizeFingerprintMode(mode)
s.mu.Unlock()
}
// FingerprintMode returns SQL fingerprint mode.
func (s *State) FingerprintMode() int {
if s == nil {
return fingerprintModeBasic
}
s.mu.RLock()
mode := NormalizeFingerprintMode(s.fingerprintMode)
s.mu.RUnlock()
return mode
}
// SetFingerprintKeepComments toggles comment preservation in generated SQL fingerprints.
func (s *State) SetFingerprintKeepComments(keep bool) {
if s == nil {
return
}
s.mu.Lock()
s.fingerprintKeepComments = keep
s.mu.Unlock()
}
// FingerprintKeepComments reports whether comments are kept in generated SQL fingerprints.
func (s *State) FingerprintKeepComments() bool {
if s == nil {
return false
}
s.mu.RLock()
keep := s.fingerprintKeepComments
s.mu.RUnlock()
return keep
}
// SetFingerprintCounterEnabled toggles in-memory SQL fingerprint hit counter.
func (s *State) SetFingerprintCounterEnabled(enabled bool) {
if s == nil {
return
}
s.mu.Lock()
s.fingerprintCounterEnabled = enabled
s.mu.Unlock()
}
// FingerprintCounterEnabled reports whether in-memory SQL fingerprint hit counter is enabled.
func (s *State) FingerprintCounterEnabled() bool {
if s == nil {
return false
}
s.mu.RLock()
enabled := s.fingerprintCounterEnabled
s.mu.RUnlock()
return enabled
}
// IncFingerprintCount increments hit count for a fingerprint.
func (s *State) IncFingerprintCount(fingerprint string) {
if s == nil || fingerprint == "" {
return
}
s.mu.Lock()
if s.fingerprintCounts == nil {
s.fingerprintCounts = make(map[string]uint64)
}
s.fingerprintCounts[fingerprint]++
s.mu.Unlock()
}
// FingerprintCountsSnapshot returns a snapshot copy of fingerprint counters.
func (s *State) FingerprintCountsSnapshot() map[string]uint64 {
if s == nil {
return map[string]uint64{}
}
s.mu.RLock()
if len(s.fingerprintCounts) == 0 {
s.mu.RUnlock()
return map[string]uint64{}
}
out := make(map[string]uint64, len(s.fingerprintCounts))
for k, v := range s.fingerprintCounts {
out[k] = v
}
s.mu.RUnlock()
return out
}
// ResetFingerprintCounts clears all fingerprint counters.
func (s *State) ResetFingerprintCounts() {
if s == nil {
return
}
s.mu.Lock()
s.fingerprintCounts = nil
s.mu.Unlock()
}