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() }