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}