270 lines
5.9 KiB
Go
270 lines
5.9 KiB
Go
|
|
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()
|
|||
|
|
}
|