001package gudusoft.gsqlparser.resolver2.iterative; 002 003import gudusoft.gsqlparser.resolver2.model.ResolutionStatistics; 004 005/** 006 * Represents a single pass of iterative resolution. 007 * 008 * <p>During iterative resolution, the resolver may need multiple passes 009 * to fully resolve all columns. Each pass attempts to resolve more columns 010 * based on information discovered in previous passes. 011 * 012 * <p>Example scenario requiring multiple passes: 013 * <pre> 014 * WITH cte1 AS (SELECT * FROM t1), -- Pass 1: Can't fully resolve * 015 * cte2 AS (SELECT c1, c2 FROM cte1) -- Pass 1: References cte1.c1, c1.c2 016 * SELECT * FROM cte2 -- Pass 2: Can now resolve based on cte2 017 * </pre> 018 * 019 * <p>Each pass tracks: 020 * - Pass number (1, 2, 3, ...) 021 * - Columns resolved in this pass 022 * - Columns still unresolved 023 * - Whether progress was made 024 * - Time taken 025 */ 026public class ResolutionPass { 027 028 /** Pass number (1-based) */ 029 private final int passNumber; 030 031 /** Statistics before this pass */ 032 private final ResolutionStatistics beforeStats; 033 034 /** Statistics after this pass */ 035 private ResolutionStatistics afterStats; 036 037 /** Number of columns resolved in this pass */ 038 private int columnsResolvedInPass; 039 040 /** Number of new inferences made in this pass */ 041 private int newInferences; 042 043 /** Time taken for this pass (milliseconds) */ 044 private long timeTaken; 045 046 /** Start time of this pass */ 047 private final long startTime; 048 049 /** Whether this pass made progress */ 050 private boolean madeProgress; 051 052 /** Reason for stopping (if this was the last pass) */ 053 private String stopReason; 054 055 public ResolutionPass(int passNumber, ResolutionStatistics beforeStats) { 056 this.passNumber = passNumber; 057 this.beforeStats = beforeStats; 058 this.startTime = System.currentTimeMillis(); 059 this.madeProgress = false; 060 } 061 062 /** 063 * Complete this pass with final statistics. 064 * 065 * @param afterStats statistics after this pass 066 */ 067 public void complete(ResolutionStatistics afterStats) { 068 this.afterStats = afterStats; 069 this.timeTaken = System.currentTimeMillis() - startTime; 070 071 // Calculate progress 072 if (beforeStats != null && afterStats != null) { 073 int beforeResolved = beforeStats.getExactMatches(); 074 int afterResolved = afterStats.getExactMatches(); 075 this.columnsResolvedInPass = afterResolved - beforeResolved; 076 this.madeProgress = this.columnsResolvedInPass > 0; 077 } 078 } 079 080 /** 081 * Set the number of new inferences made in this pass. 082 * 083 * @param count inference count 084 */ 085 public void setNewInferences(int count) { 086 this.newInferences = count; 087 if (count > 0) { 088 this.madeProgress = true; 089 } 090 } 091 092 /** 093 * Set the reason why iteration stopped after this pass. 094 * 095 * @param reason stop reason 096 */ 097 public void setStopReason(String reason) { 098 this.stopReason = reason; 099 } 100 101 public int getPassNumber() { 102 return passNumber; 103 } 104 105 public ResolutionStatistics getBeforeStats() { 106 return beforeStats; 107 } 108 109 public ResolutionStatistics getAfterStats() { 110 return afterStats; 111 } 112 113 public int getColumnsResolvedInPass() { 114 return columnsResolvedInPass; 115 } 116 117 public int getNewInferences() { 118 return newInferences; 119 } 120 121 public long getTimeTaken() { 122 return timeTaken; 123 } 124 125 public boolean madeProgress() { 126 return madeProgress; 127 } 128 129 public String getStopReason() { 130 return stopReason; 131 } 132 133 /** 134 * Get a summary of this pass. 135 * 136 * @return summary string 137 */ 138 public String getSummary() { 139 StringBuilder sb = new StringBuilder(); 140 sb.append("Pass ").append(passNumber).append(": "); 141 142 if (afterStats != null) { 143 sb.append("resolved ").append(columnsResolvedInPass).append(" columns"); 144 if (newInferences > 0) { 145 sb.append(", made ").append(newInferences).append(" inferences"); 146 } 147 sb.append(" (").append(timeTaken).append("ms)"); 148 } else { 149 sb.append("incomplete"); 150 } 151 152 if (stopReason != null) { 153 sb.append(" - ").append(stopReason); 154 } 155 156 return sb.toString(); 157 } 158 159 @Override 160 public String toString() { 161 return getSummary(); 162 } 163}