001package gudusoft.gsqlparser.resolver2.iterative; 002 003import gudusoft.gsqlparser.resolver2.model.ResolutionStatistics; 004 005/** 006 * Adaptive resolution strategy that adjusts based on query complexity. 007 * 008 * <p>This strategy analyzes the resolution progress and adapts its behavior: 009 * - If progress is good: Continue with current approach 010 * - If progress stalls: Enable more aggressive techniques (inference, expansion) 011 * - If query is complex: Use more iterations 012 * - If query is simple: Use fewer iterations 013 * 014 * <p>Adaptation criteria: 015 * - Resolution rate (% of columns resolved) 016 * - Progress per pass (columns resolved in each iteration) 017 * - Query complexity (number of CTEs, subqueries, etc.) 018 * 019 * <p>Example behavior: 020 * <pre> 021 * Simple query (SELECT a, b FROM t1): 022 * Pass 1: 100% resolved -> STOP (no need for more passes) 023 * 024 * Complex query (multiple nested CTEs): 025 * Pass 1: 30% resolved -> continue 026 * Pass 2: 60% resolved -> enable inference 027 * Pass 3: 85% resolved -> enable aggressive expansion 028 * Pass 4: 95% resolved -> final cleanup 029 * </pre> 030 */ 031public class AdaptiveResolutionStrategy implements ResolutionStrategy { 032 033 /** Threshold for "good" progress rate */ 034 private static final double GOOD_PROGRESS_THRESHOLD = 0.2; // 20% per pass 035 036 /** Threshold for "slow" progress rate */ 037 private static final double SLOW_PROGRESS_THRESHOLD = 0.05; // 5% per pass 038 039 /** Current adaptive state */ 040 private AdaptiveState currentState; 041 042 /** Previous resolution rate */ 043 private double previousResolutionRate; 044 045 /** Number of consecutive slow passes */ 046 private int slowPassCount; 047 048 public AdaptiveResolutionStrategy() { 049 this.currentState = AdaptiveState.CONSERVATIVE; 050 this.previousResolutionRate = 0.0; 051 this.slowPassCount = 0; 052 } 053 054 @Override 055 public String getName() { 056 return "Adaptive"; 057 } 058 059 @Override 060 public boolean shouldPerformInference(int passNumber, ResolutionStatistics previousStats) { 061 // Always enable inference in aggressive mode 062 if (currentState == AdaptiveState.AGGRESSIVE) { 063 return true; 064 } 065 066 // Enable inference from pass 2 in normal mode 067 if (currentState == AdaptiveState.NORMAL && passNumber >= 2) { 068 return true; 069 } 070 071 // Conservative mode: only if progress is slow 072 if (currentState == AdaptiveState.CONSERVATIVE) { 073 return slowPassCount >= 2; 074 } 075 076 return false; 077 } 078 079 @Override 080 public boolean shouldExpandStars(int passNumber, ResolutionStatistics previousStats) { 081 // Expand stars based on state 082 switch (currentState) { 083 case AGGRESSIVE: 084 return passNumber >= 1; // Expand immediately 085 case NORMAL: 086 return passNumber >= 2; // Expand from pass 2 087 case CONSERVATIVE: 088 return passNumber >= 3; // Wait until pass 3 089 default: 090 return passNumber >= 2; 091 } 092 } 093 094 @Override 095 public boolean shouldPushDownColumns(int passNumber, ResolutionStatistics previousStats) { 096 // Push-down is expensive, so enable it strategically 097 switch (currentState) { 098 case AGGRESSIVE: 099 return passNumber >= 2; // Enable early in aggressive mode 100 case NORMAL: 101 return passNumber >= 3; // Enable later in normal mode 102 case CONSERVATIVE: 103 return passNumber >= 4; // Enable late in conservative mode 104 default: 105 return passNumber >= 3; 106 } 107 } 108 109 @Override 110 public void preparePass(int passNumber, ResolutionStatistics previousStats) { 111 if (previousStats == null || passNumber == 1) { 112 // First pass: start conservative 113 currentState = AdaptiveState.CONSERVATIVE; 114 return; 115 } 116 117 // Calculate progress metrics 118 int total = previousStats.getTotalReferences(); 119 int resolved = previousStats.getExactMatches(); 120 121 double resolutionRate = total > 0 ? (double) resolved / total : 0.0; 122 double progressRate = resolutionRate - previousResolutionRate; 123 124 // Adapt state based on progress 125 if (progressRate >= GOOD_PROGRESS_THRESHOLD) { 126 // Good progress: stay in or move to normal mode 127 if (currentState == AdaptiveState.CONSERVATIVE) { 128 currentState = AdaptiveState.NORMAL; 129 } 130 slowPassCount = 0; 131 } else if (progressRate <= SLOW_PROGRESS_THRESHOLD) { 132 // Slow progress: become more aggressive 133 slowPassCount++; 134 if (slowPassCount >= 2) { 135 if (currentState == AdaptiveState.CONSERVATIVE) { 136 currentState = AdaptiveState.NORMAL; 137 } else if (currentState == AdaptiveState.NORMAL) { 138 currentState = AdaptiveState.AGGRESSIVE; 139 } 140 } 141 } else { 142 // Moderate progress: stay in normal mode 143 if (currentState == AdaptiveState.CONSERVATIVE) { 144 currentState = AdaptiveState.NORMAL; 145 } 146 slowPassCount = 0; 147 } 148 149 previousResolutionRate = resolutionRate; 150 } 151 152 @Override 153 public String getDescription() { 154 return "Adaptive resolution strategy. " + 155 "Adjusts behavior based on resolution progress. " + 156 "States: Conservative -> Normal -> Aggressive."; 157 } 158 159 /** 160 * Get the current adaptive state. 161 * 162 * @return current state 163 */ 164 public AdaptiveState getCurrentState() { 165 return currentState; 166 } 167 168 @Override 169 public String toString() { 170 return getName() + " strategy (state: " + currentState + ")"; 171 } 172 173 /** 174 * Adaptive states. 175 */ 176 public enum AdaptiveState { 177 /** Conservative: minimal inference and expansion */ 178 CONSERVATIVE, 179 180 /** Normal: standard inference and expansion */ 181 NORMAL, 182 183 /** Aggressive: maximum inference and expansion */ 184 AGGRESSIVE 185 } 186}