1 5 package org.h2.index; 6 7 import java.sql.SQLException ; 8 9 import org.h2.command.dml.Query; 10 import org.h2.engine.Constants; 11 import org.h2.engine.Session; 12 import org.h2.expression.Comparison; 13 import org.h2.expression.Parameter; 14 import org.h2.expression.ValueExpression; 15 import org.h2.message.Message; 16 import org.h2.result.LocalResult; 17 import org.h2.result.Row; 18 import org.h2.result.SearchRow; 19 import org.h2.table.Column; 20 import org.h2.table.TableView; 21 import org.h2.util.IntArray; 22 import org.h2.util.SmallLRUCache; 23 import org.h2.util.ObjectArray; 24 import org.h2.value.Value; 25 26 public class ViewIndex extends Index { 27 28 private String querySQL; 29 private ObjectArray originalParameters; 30 private Parameter[] params; 31 32 private SmallLRUCache costCache = new SmallLRUCache(Constants.VIEW_COST_CACHE_SIZE); 33 34 private Value[] lastParameters; 35 private long lastEvaluated; 36 private LocalResult lastResult; 37 38 public ViewIndex(TableView view, String querySQL, ObjectArray originalParameters) { 39 super(view, 0, null, null, IndexType.createNonUnique(false)); 40 this.querySQL = querySQL; 41 this.originalParameters = originalParameters; 42 } 43 44 public String getPlanSQL() { 45 return querySQL; 46 } 47 48 public void close(Session session) throws SQLException { 49 } 50 51 public void add(Session session, Row row) throws SQLException { 52 throw Message.getUnsupportedException(); 53 } 54 55 public void remove(Session session, Row row) throws SQLException { 56 throw Message.getUnsupportedException(); 57 } 58 59 private int getComparisonType(int mask) { 60 if((mask & IndexCondition.EQUALITY) == IndexCondition.EQUALITY) { 61 return Comparison.EQUAL; 62 } else if ((mask & IndexCondition.RANGE) == IndexCondition.RANGE) { 63 return Comparison.BIGGER_EQUAL; 65 } else if ((mask & IndexCondition.START) == IndexCondition.START) { 66 return Comparison.BIGGER_EQUAL; 67 } else if ((mask & IndexCondition.END) == IndexCondition.END) { 68 return Comparison.SMALLER_EQUAL; 69 } 70 throw Message.getInternalError("unsupported mask "+mask); 71 } 72 73 private static class CostElement { 74 long evaluatedAt; 75 double cost; 76 } 77 78 public double getCost(Session session, int[] masks) throws SQLException { 79 IntArray masksArray = new IntArray(masks == null ? new int[0] : masks); 80 CostElement cachedCost = (CostElement) costCache.get(masksArray); 81 if(cachedCost != null) { 82 long time = System.currentTimeMillis(); 83 if(time < cachedCost.evaluatedAt + Constants.VIEW_COST_CACHE_MAX_AGE) { 84 return cachedCost.cost; 85 } 86 } 87 Query query = (Query)session.prepare(querySQL, true); 88 IntArray paramIndex = new IntArray(); 89 if(masks == null) { 90 columns = new Column[0]; 91 params = new Parameter[0]; 92 } else { 93 for(int i=0; i<masks.length; i++) { 94 int mask = masks[i]; 95 if(mask == 0) { 96 continue; 97 } 98 paramIndex.add(i); 99 } 100 int len = paramIndex.size(); 101 columns = new Column[len]; 102 params = new Parameter[len]; 103 for(int i=0; i<len; i++) { 104 int idx = paramIndex.get(i); 105 Column col = table.getColumn(idx); 106 columns[i] = col; 107 Parameter param = new Parameter(0); 108 params[i] = param; 109 int mask = masks[idx]; 110 int comparisonType = getComparisonType(mask); 111 query.addGlobalCondition(param, idx, comparisonType); 112 } 113 String sql = query.getSQL(); 114 query = (Query)session.prepare(sql); 115 } 116 double cost = query.getCost(); 117 cachedCost = new CostElement(); 118 cachedCost.evaluatedAt = System.currentTimeMillis(); 119 cachedCost.cost = cost; 120 costCache.put(masksArray, cachedCost); 121 return cost; 122 } 123 124 public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException { 125 Query query = (Query)session.prepare(querySQL, true); 126 ObjectArray paramList = query.getParameters(); 127 for(int i=0; first != null && i<first.getColumnCount(); i++) { 128 Value v = first.getValue(i); 129 if(v != null) { 130 query.addGlobalCondition(ValueExpression.get(v), i, Comparison.BIGGER_EQUAL); 131 } 132 } 133 for(int i=0; last != null && i<last.getColumnCount(); i++) { 134 Value v = last.getValue(i); 135 if(v != null) { 136 query.addGlobalCondition(ValueExpression.get(v), i, Comparison.SMALLER_EQUAL); 137 } 138 } 139 for(int i=0; originalParameters != null && i<originalParameters.size(); i++) { 140 Parameter orig = (Parameter) originalParameters.get(i); 141 Parameter param = (Parameter) paramList.get(i); 142 Value value = orig.getValue(session); 143 param.setValue(value); 144 } 145 boolean canReuse = first == null && last == null; 146 long now = session.getDatabase().getModificationDataId(); 147 Value[] params = query.getParameterValues(); 148 if(session.getDatabase().getOptimizeReuseResults()) { 149 if(lastResult != null && canReuse) { 150 if(query.sameResultAsLast(session, params, lastParameters, lastEvaluated)) { 151 lastResult = lastResult.createShallowCopy(session); 152 lastResult.reset(); 153 return new ViewCursor(table, lastResult); 154 } 155 } 156 } 157 query.setSession(session); 158 LocalResult result = query.query(0); 159 if(canReuse) { 160 lastResult = result; 161 lastParameters = params; 162 lastEvaluated = now; 163 } 164 return new ViewCursor(table, result); 165 } 166 167 public int getCost(int[] masks) throws SQLException { 168 if(masks != null) { 169 throw Message.getUnsupportedException(); 170 } 171 return Integer.MAX_VALUE; 172 } 173 174 public void remove(Session session) throws SQLException { 175 throw Message.getUnsupportedException(); 176 } 177 178 public void truncate(Session session) throws SQLException { 179 throw Message.getUnsupportedException(); 180 } 181 182 public void checkRename() throws SQLException { 183 throw Message.getUnsupportedException(); 184 } 185 186 public boolean needRebuild() { 187 return false; 188 } 189 190 public boolean canGetFirstOrLast(boolean first) { 191 return false; 192 } 193 194 public Value findFirstOrLast(Session session, boolean first) throws SQLException { 195 throw Message.getUnsupportedException(); 196 } 197 198 } 199 | Popular Tags |