1 5 package org.h2.table; 6 7 import java.sql.SQLException ; 8 9 import org.h2.engine.Constants; 10 import org.h2.engine.Right; 11 import org.h2.engine.Session; 12 import org.h2.expression.ConditionAndOr; 13 import org.h2.expression.Expression; 14 import org.h2.index.Cursor; 15 import org.h2.index.Index; 16 import org.h2.index.IndexCondition; 17 import org.h2.message.Message; 18 import org.h2.result.Row; 19 import org.h2.result.SearchRow; 20 import org.h2.util.ObjectArray; 21 import org.h2.util.StringUtils; 22 import org.h2.value.Value; 23 24 27 public class TableFilter implements ColumnResolver { 28 private Session session; 29 private Table table; 30 private String alias; 31 private static final int BEFORE_FIRST = 0, FOUND = 1, AFTER_LAST = 2, NULL_ROW = 3; 32 private Index index; 33 private Cursor cursor; 34 private int scanCount; 35 private boolean used; 37 private ObjectArray indexConditions = new ObjectArray(); 39 40 private Expression filterCondition; 42 43 private Expression joinCondition; 45 private Row current; 46 private int state; 47 private TableFilter join; 48 private boolean outerJoin; 49 private boolean foundOne; 50 private Expression fullCondition; 51 private boolean rightsChecked; 52 53 public TableFilter(Session session, Table table, String alias, boolean rightsChecked) { 54 this.session = session; 55 this.table = table; 56 this.alias = alias; 57 this.rightsChecked = rightsChecked; 58 } 59 60 public Session getSession() { 61 return session; 62 } 63 64 public Table getTable() { 65 return table; 66 } 67 68 public void lock(Session session, boolean exclusive) throws SQLException { 69 if(!rightsChecked) { 70 session.getUser().checkRight(table, Right.SELECT); 71 } 72 table.lock(session, exclusive); 73 if (join != null) { 74 join.lock(session, exclusive); 75 } 76 } 77 78 public PlanItem getBestPlanItem(Session session) throws SQLException { 79 PlanItem item; 80 if (indexConditions.size() == 0) { 81 item = new PlanItem(); 82 item.index = table.getScanIndex(session); 83 item.cost = item.index.getCost(null); 84 } else { 85 int len = table.getColumns().length; 86 int[] masks = new int[len]; 87 for (int i = 0; i < indexConditions.size(); i++) { 88 IndexCondition condition = (IndexCondition) indexConditions.get(i); 89 if (condition.isEvaluatable()) { 90 if(condition.isAlwaysFalse()) { 91 masks = null; 92 break; 93 } else { 94 int id = condition.getColumn().getColumnId(); 95 masks[id] |= condition.getMask(); 96 } 97 } 98 } 99 item = table.getBestPlanItem(session, masks); 100 } 101 if(join != null) { 102 TableFilter j = join; 103 do { 105 Expression e = j.getJoinCondition(); 106 if(e != null) { 107 e.setEvaluatable(this, true); 108 } 109 j = j.getJoin(); 110 } while(j != null); 111 item.joinPlan = join.getBestPlanItem(session); 112 item.cost += item.cost * item.joinPlan.cost; 114 } 115 return item; 116 } 117 118 public void setPlanItem(PlanItem item) { 119 this.index = item.index; 120 if(join != null && item.joinPlan!=null) { 121 join.setPlanItem(item.joinPlan); 122 } 123 } 124 125 public void prepare() { 126 for (int i = 0; i < indexConditions.size(); i++) { 128 IndexCondition condition = (IndexCondition) indexConditions.get(i); 129 if(!condition.isAlwaysFalse()) { 130 Column col = condition.getColumn(); 131 if(index.getColumnIndex(col) < 0) { 132 indexConditions.remove(i); 133 i--; 134 } 135 } 136 } 137 if(join != null) { 138 if(Constants.CHECK && join==this) { 139 throw Message.getInternalError("self join"); 140 } 141 join.prepare(); 142 } 143 } 144 145 public void startQuery() { 146 scanCount = 0; 147 if(join != null) { 148 join.startQuery(); 149 } 150 } 151 152 public void reset() throws SQLException { 153 if (join != null) { 154 join.reset(); 155 } 156 state = BEFORE_FIRST; 157 foundOne = false; 158 } 159 160 public boolean next() throws SQLException { 161 boolean alwaysFalse = false; 162 if (state == AFTER_LAST) { 163 return false; 164 } else if (state == BEFORE_FIRST) { 165 SearchRow start = null, end = null; 166 for (int i = 0; i < indexConditions.size(); i++) { 167 IndexCondition condition = (IndexCondition) indexConditions.get(i); 168 if (condition.isAlwaysFalse()) { 169 alwaysFalse = true; 170 break; 171 } 172 Column column = condition.getColumn(); 173 int type = column.getType(); 174 int id = column.getColumnId(); 175 Value v = condition.getCurrentValue(session).convertTo(type); 176 if (condition.isStart()) { 177 if(start == null) { 179 start = table.getTemplateRow(); 180 } 181 start.setValue(id, v); 182 } 183 if (condition.isEnd()) { 184 if(end == null) { 186 end = table.getTemplateRow(); 187 } 188 end.setValue(id, v); 189 } 190 } 191 if(!alwaysFalse) { 192 cursor = index.find(session, start, end); 193 if(join != null) { 194 join.reset(); 195 } 196 } 197 } else { 198 if(join != null && join.next()) { 201 return true; 202 } 203 } 204 while(true) { 205 if(state == NULL_ROW) { 207 break; 208 } 209 if(alwaysFalse) { 210 state = AFTER_LAST; 211 } else { 212 scanCount++; 213 if(cursor.next()) { 214 current = cursor.get(); 215 state = FOUND; 216 } else { 217 state = AFTER_LAST; 218 } 219 } 220 if(state == AFTER_LAST) { 222 if(outerJoin && !foundOne) { 223 state = NULL_ROW; 224 current = table.getNullRow(); 225 } else { 226 break; 227 } 228 } 229 if(!isOk(filterCondition)) { 230 continue; 231 } 232 boolean joinConditionOk = isOk(joinCondition); 233 if(state==FOUND && joinConditionOk) { 234 foundOne = true; 235 } 236 if(join != null) { 237 join.reset(); 238 if(!join.next()) { 239 continue; 240 } 241 } 242 if(state==NULL_ROW || joinConditionOk) { 244 return true; 245 } 246 } 247 state = AFTER_LAST; 248 return false; 249 } 250 251 private boolean isOk(Expression condition) throws SQLException { 252 if(condition == null) { 253 return true; 254 } 255 return Boolean.TRUE.equals(condition.getBooleanValue(session)); 256 } 257 258 public Row get() { 259 return current; 260 } 261 262 public void set(Row current) { 263 this.current = current; 265 } 266 267 public String getTableAlias() { 268 if (alias != null) { 269 return alias; 270 } 271 return table.getName(); 272 } 273 274 public void addIndexCondition(IndexCondition condition) { 275 indexConditions.add(condition); 276 } 277 278 public void addFilterCondition(Expression condition, boolean join) { 279 if(join) { 280 if(joinCondition == null) { 281 joinCondition = condition; 282 } else { 283 joinCondition = new ConditionAndOr(ConditionAndOr.AND, joinCondition, condition); 284 } 285 } else { 286 if (filterCondition == null) { 287 filterCondition = condition; 288 } else { 289 filterCondition = new ConditionAndOr(ConditionAndOr.AND, filterCondition, condition); 290 } 291 } 292 } 293 294 public void addJoin(TableFilter filter, boolean outer, Expression on) throws SQLException { 295 if(on != null) { 296 on.mapColumns(this, 0); 297 } 298 if(join == null) { 299 this.join = filter; 300 filter.outerJoin = outer; 301 if(on != null) { 302 TableFilter f = filter; 303 do { 304 on.mapColumns(f, 0); 305 f.addFilterCondition(on, true); 306 on.createIndexConditions(f); 307 f = f.join; 308 } while(f != null); 309 } 310 } else { 311 join.addJoin(filter, outer, on); 312 } 313 if(on != null) { 314 on.optimize(session); 315 } 316 } 317 318 public TableFilter getJoin() { 319 return join; 320 } 321 322 public boolean isJoinOuter() { 323 return outerJoin; 324 } 325 326 public String getPlanSQL(boolean join) { 327 StringBuffer buff = new StringBuffer (); 328 if(join) { 329 if(outerJoin) { 330 buff.append("LEFT OUTER JOIN "); 331 } else { 332 buff.append("INNER JOIN "); 333 } 334 } 335 buff.append(table.getSQL()); 336 if(alias != null && !table.getName().equals(alias)) { 337 buff.append(' '); 338 buff.append(alias); 339 } 340 buff.append(" /* "); 341 buff.append(index.getPlanSQL()); 342 if(indexConditions.size() > 0) { 343 buff.append(": "); 344 for (int i = 0; i < indexConditions.size(); i++) { 345 IndexCondition condition = (IndexCondition) indexConditions.get(i); 346 if(i>0) { 347 buff.append(" AND "); 348 } 349 buff.append(condition.getSQL()); 350 } 351 } 352 buff.append(" */"); 353 if(joinCondition != null) { 354 buff.append(" ON "); 355 buff.append(StringUtils.unEnclose(joinCondition.getSQL())); 356 } 357 if(filterCondition != null) { 358 buff.append(" /* WHERE "); 359 buff.append(StringUtils.unEnclose(filterCondition.getSQL())); 360 buff.append("*/"); 361 } 362 return buff.toString(); 363 } 364 365 public void removeUnusableIndexConditions() { 366 for(int i=0; i<indexConditions.size(); i++) { 367 IndexCondition cond = (IndexCondition) indexConditions.get(i); 368 if(!cond.isEvaluatable()) { 369 indexConditions.remove(i--); 370 } 371 } 372 } 373 374 public Index getIndex() { 375 return index; 376 } 377 378 public void setIndex(Index index) { 379 this.index = index; 380 } 381 382 public void setUsed(boolean used) { 383 this.used = used; 384 } 385 386 public boolean getUsed() { 387 return used; 388 } 389 390 public void setSession(Session session) { 391 this.session = session; 392 } 393 394 public void removeJoin() { 395 this.join = null; 396 } 397 398 public Expression getJoinCondition() { 399 return joinCondition; 400 } 401 402 public void removeJoinCondition() { 403 this.joinCondition = null; 404 } 405 406 public Expression getFilterCondition() { 407 return filterCondition; 408 } 409 410 public void removeFilterCondition() { 411 this.filterCondition = null; 412 } 413 414 public void setFullCondition(Expression condition) { 415 this.fullCondition = condition; 416 if(join != null) { 417 join.setFullCondition(condition); 418 } 419 } 420 421 public void optimizeFullCondition(boolean fromOuterJoin) { 422 if(fullCondition != null) { 423 fullCondition.addFilterConditions(this, fromOuterJoin || outerJoin); 424 if(join != null) { 425 join.optimizeFullCondition(fromOuterJoin || outerJoin); 426 } 427 } 428 } 429 430 public void setEvaluatable(TableFilter filter, boolean b) { 431 if(filterCondition != null) { 432 filterCondition.setEvaluatable(filter, b); 433 } 434 if(joinCondition != null) { 435 joinCondition.setEvaluatable(filter, b); 436 } 437 if(join != null) { 438 join.setEvaluatable(filter, b); 439 } 440 } 441 442 public String getSchemaName() { 443 return table.getSchema().getName(); 444 } 445 446 public Column[] getColumns() { 447 return table.getColumns(); 448 } 449 450 public Value getValue(Column column) { 451 return current == null ? null : current.getValue(column.getColumnId()); 452 } 453 454 public TableFilter getTableFilter() { 455 return this; 456 } 457 458 } 459 | Popular Tags |