📄 tablefilter.java
字号:
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.table;
import java.sql.SQLException;
import org.h2.command.Parser;
import org.h2.command.dml.Select;
import org.h2.constant.SysProperties;
import org.h2.engine.Right;
import org.h2.engine.Session;
import org.h2.expression.ConditionAndOr;
import org.h2.expression.Expression;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexCondition;
import org.h2.message.Message;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.util.ObjectArray;
import org.h2.util.StringUtils;
import org.h2.value.Value;
/**
* A table filter represents a table that is used in a query. There is one such
* object whenever a table (or view) is used in a query. For example the
* following query has 2 table filters: SELECT * FROM TEST T1, TEST T2.
*/
public class TableFilter implements ColumnResolver {
private static final int BEFORE_FIRST = 0, FOUND = 1, AFTER_LAST = 2, NULL_ROW = 3;
private final Table table;
private final Select select;
private String alias;
private Session session;
private Index index;
private IndexColumn[] indexColumns;
private Cursor cursor;
private int scanCount;
private boolean used; // used in the plan
// conditions that can be used for direct index lookup (start or end)
private final ObjectArray indexConditions = new ObjectArray();
// conditions that can't be used for index lookup,
// but for row filter for this table (ID=ID, NAME LIKE '%X%')
private Expression filterCondition;
// the complete join condition
private Expression joinCondition;
private SearchRow currentSearchRow;
private Row current;
private int state;
private TableFilter join;
private boolean outerJoin;
private boolean foundOne;
private Expression fullCondition;
public TableFilter(Session session, Table table, String alias, boolean rightsChecked, Select select)
throws SQLException {
this.session = session;
this.table = table;
this.alias = alias;
this.select = select;
if (!rightsChecked) {
session.getUser().checkRight(table, Right.SELECT);
}
}
public Select getSelect() {
return select;
}
public Table getTable() {
return table;
}
public void lock(Session session, boolean exclusive, boolean force) throws SQLException {
table.lock(session, exclusive, force);
if (join != null) {
join.lock(session, exclusive, force);
}
}
public PlanItem getBestPlanItem(Session session) throws SQLException {
PlanItem item;
if (indexConditions.size() == 0) {
item = new PlanItem();
item.setIndex(table.getScanIndex(session));
item.cost = item.getIndex().getCost(session, null);
} else {
int len = table.getColumns().length;
int[] masks = new int[len];
for (int i = 0; i < indexConditions.size(); i++) {
IndexCondition condition = (IndexCondition) indexConditions.get(i);
if (condition.isEvaluatable()) {
if (condition.isAlwaysFalse()) {
masks = null;
break;
} else {
int id = condition.getColumn().getColumnId();
masks[id] |= condition.getMask();
}
}
}
item = table.getBestPlanItem(session, masks);
}
if (join != null) {
setEvaluatable(join);
item.setJoinPlan(join.getBestPlanItem(session));
// TODO optimizer: calculate cost of a join: should use separate
// expected row number and lookup cost
item.cost += item.cost * item.getJoinPlan().cost;
}
return item;
}
private void setEvaluatable(TableFilter join) {
// this table filter is now evaluatable - in all sub-joins
do {
Expression e = join.getJoinCondition();
if (e != null) {
e.setEvaluatable(this, true);
}
join = join.getJoin();
} while (join != null);
}
public void setPlanItem(PlanItem item) {
setIndex(item.getIndex());
if (join != null) {
if (item.getJoinPlan() != null) {
join.setPlanItem(item.getJoinPlan());
}
}
}
public void prepare() throws SQLException {
// forget all unused index conditions
for (int i = 0; i < indexConditions.size(); i++) {
IndexCondition condition = (IndexCondition) indexConditions.get(i);
if (!condition.isAlwaysFalse()) {
Column col = condition.getColumn();
if (index.getColumnIndex(col) < 0) {
indexConditions.remove(i);
i--;
}
}
}
if (join != null) {
if (SysProperties.CHECK && join == this) {
throw Message.getInternalError("self join");
}
join.prepare();
}
if (filterCondition != null) {
filterCondition = filterCondition.optimize(session);
}
if (joinCondition != null) {
joinCondition = joinCondition.optimize(session);
}
}
public void startQuery(Session session) throws SQLException {
this.session = session;
scanCount = 0;
if (join != null) {
join.startQuery(session);
}
}
public void reset() {
if (join != null) {
join.reset();
}
state = BEFORE_FIRST;
foundOne = false;
}
public boolean next() throws SQLException {
boolean alwaysFalse = false;
if (state == AFTER_LAST) {
return false;
} else if (state == BEFORE_FIRST) {
SearchRow start = null, end = null;
for (int i = 0; i < indexConditions.size(); i++) {
IndexCondition condition = (IndexCondition) indexConditions.get(i);
if (condition.isAlwaysFalse()) {
alwaysFalse = true;
break;
}
Column column = condition.getColumn();
int type = column.getType();
int id = column.getColumnId();
Value v = condition.getCurrentValue(session).convertTo(type);
boolean isStart = condition.isStart(), isEnd = condition.isEnd();
IndexColumn idxCol = indexColumns[id];
if (idxCol != null && (idxCol.sortType & SortOrder.DESCENDING) != 0) {
// if the index column is sorted the other way, we swap end and start
// NULLS_FIRST / NULLS_LAST is not a problem, as nulls never match anyway
boolean temp = isStart;
isStart = isEnd;
isEnd = temp;
}
if (isStart) {
// TODO index: start.setExpression(id, bigger(start.getValue(id), e));
if (start == null) {
start = table.getTemplateRow();
}
start.setValue(id, v);
}
if (isEnd) {
// TODO index: end.setExpression(id, smaller(end.getExpression(id), e));
if (end == null) {
end = table.getTemplateRow();
}
end.setValue(id, v);
}
}
if (!alwaysFalse) {
cursor = index.find(session, start, end);
if (join != null) {
join.reset();
}
}
} else {
// state == FOUND || LAST_ROW
// the last row was ok - try next row of the join
if (join != null && join.next()) {
return true;
}
}
while (true) {
// go to the next row
if (state == NULL_ROW) {
break;
}
if (alwaysFalse) {
state = AFTER_LAST;
} else {
if ((++scanCount & 4095) == 0) {
checkTimeout();
}
if (cursor.next()) {
currentSearchRow = cursor.getSearchRow();
current = null;
// cursor.get();
state = FOUND;
} else {
state = AFTER_LAST;
}
}
// if no more rows found, try the null row (for outer joins only)
if (state == AFTER_LAST) {
if (outerJoin && !foundOne) {
state = NULL_ROW;
current = table.getNullRow();
currentSearchRow = current;
} else {
break;
}
}
if (!isOk(filterCondition)) {
continue;
}
boolean joinConditionOk = isOk(joinCondition);
if (state == FOUND) {
if (joinConditionOk) {
foundOne = true;
} else {
continue;
}
}
if (join != null) {
join.reset();
if (!join.next()) {
continue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -