001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.table;
007:
008: import java.sql.SQLException;
009: import java.util.HashMap;
010:
011: import org.h2.engine.Session;
012: import org.h2.expression.Expression;
013: import org.h2.expression.ExpressionVisitor;
014: import org.h2.util.ObjectArray;
015:
016: /**
017: * A possible query execution plan. The time required to execute a query depends
018: * on the order the tables are accessed.
019: */
020: public class Plan {
021: private final TableFilter[] filters;
022: private final HashMap planItems = new HashMap();
023: private final Expression[] allConditions;
024: private final TableFilter[] allFilters;
025:
026: public Plan(TableFilter[] filters, int count, Expression condition) {
027: this .filters = new TableFilter[count];
028: System.arraycopy(filters, 0, this .filters, 0, count);
029: ObjectArray allCond = new ObjectArray();
030: ObjectArray all = new ObjectArray();
031: if (condition != null) {
032: allCond.add(condition);
033: }
034: for (int i = 0; i < count; i++) {
035: TableFilter f = filters[i];
036: do {
037: all.add(f);
038: if (f.getJoinCondition() != null) {
039: allCond.add(f.getJoinCondition());
040: }
041: f = f.getJoin();
042: } while (f != null);
043: }
044: allConditions = new Expression[allCond.size()];
045: allCond.toArray(allConditions);
046: allFilters = new TableFilter[all.size()];
047: all.toArray(allFilters);
048: }
049:
050: public PlanItem getItem(TableFilter filter) {
051: return (PlanItem) planItems.get(filter);
052: }
053:
054: public TableFilter[] getFilters() {
055: return filters;
056: }
057:
058: public void removeUnusableIndexConditions() {
059: for (int i = 0; i < allFilters.length; i++) {
060: TableFilter f = allFilters[i];
061: setEvaluatable(f, true);
062: if (i < allFilters.length - 1) {
063: // the last table doesn't need the optimization,
064: // otherwise the expression is calculated twice unnecessarily
065: // (not that bad but not optimal)
066: f.optimizeFullCondition(false);
067: }
068: f.removeUnusableIndexConditions();
069: }
070: for (int i = 0; i < allFilters.length; i++) {
071: TableFilter f = allFilters[i];
072: setEvaluatable(f, false);
073: }
074: }
075:
076: public double calculateCost(Session session) throws SQLException {
077: double cost = 1;
078: boolean invalidPlan = false;
079: for (int i = 0; i < allFilters.length; i++) {
080: TableFilter tableFilter = allFilters[i];
081: PlanItem item = tableFilter.getBestPlanItem(session);
082: planItems.put(tableFilter, item);
083: cost += cost * item.cost;
084: setEvaluatable(tableFilter, true);
085: Expression on = tableFilter.getJoinCondition();
086: if (on != null) {
087: if (!on.isEverything(ExpressionVisitor.EVALUATABLE)) {
088: invalidPlan = true;
089: break;
090: }
091: }
092: }
093: if (invalidPlan) {
094: cost = 1. / 0.; // Infinity
095: }
096: for (int i = 0; i < allFilters.length; i++) {
097: setEvaluatable(allFilters[i], false);
098: }
099: return cost;
100: }
101:
102: private void setEvaluatable(TableFilter filter, boolean b) {
103: for (int j = 0; j < allConditions.length; j++) {
104: allConditions[j].setEvaluatable(filter, b);
105: }
106: }
107: }
|