提交 c266fa0a authored 作者: S.Vladykin's avatar S.Vladykin

WIP subquery batched join

上级 98b5eba7
......@@ -71,6 +71,8 @@ public abstract class Query extends Prepared {
super(session);
}
public abstract boolean isUnion();
/**
* Execute the query without checking the cache. If a target is specified,
* the results are written to it, and the method returns null. If no target
......
......@@ -87,6 +87,11 @@ public class Select extends Query {
super(session);
}
@Override
public boolean isUnion() {
return false;
}
/**
* Add a table to the query.
*
......@@ -942,7 +947,9 @@ public class Select extends Query {
}
expressionArray = new Expression[expressions.size()];
expressions.toArray(expressionArray);
if (!session.isParsingView()) {
topTableFilter.prepareBatch(0);
}
isPrepared = true;
}
......
......@@ -7,7 +7,6 @@ package org.h2.command.dml;
import java.util.ArrayList;
import java.util.HashSet;
import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface;
import org.h2.engine.Session;
......@@ -72,6 +71,11 @@ public class SelectUnion extends Query {
this.left = query;
}
@Override
public boolean isUnion() {
return true;
}
public void setUnionType(int type) {
this.unionType = type;
}
......
......@@ -6,9 +6,12 @@
package org.h2.index;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import org.h2.api.ErrorCode;
import org.h2.command.Prepared;
import org.h2.command.dml.Query;
import org.h2.command.dml.Select;
import org.h2.command.dml.SelectUnion;
import org.h2.engine.Constants;
import org.h2.engine.Session;
......@@ -21,6 +24,7 @@ import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.JoinBatch;
import org.h2.table.SubQueryInfo;
import org.h2.table.TableFilter;
import org.h2.table.TableView;
......@@ -93,6 +97,46 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
}
}
@Override
public IndexLookupBatch createLookupBatch(TableFilter filter) {
if (recursive) {
// we do not support batching for recursive queries
return null;
}
if (query.isUnion()) {
return createLookupBatchUnion((SelectUnion) query);
}
return createLookupBatchSimple((Select) query);
}
private IndexLookupBatch createLookupBatchSimple(Select select) {
// here we have already prepared plan for our sub-query,
// thus select already contains join batch for it (if it has to)
JoinBatch joinBatch = select.getJoinBatch();
if (joinBatch == null) {
// our sub-query itself is not batched, will run usual way
return null;
}
return joinBatch.getLookupBatch(0);
}
private IndexLookupBatch createLookupBatchUnion(SelectUnion union) {
Query left = union.getLeft();
IndexLookupBatch leftLookupBatch = left.isUnion() ?
createLookupBatchUnion((SelectUnion) left):
createLookupBatchSimple((Select) left);
Query right = union.getRight();
IndexLookupBatch rightLookupBatch = right.isUnion() ?
createLookupBatchUnion((SelectUnion) right) :
createLookupBatchSimple((Select) right);
if (leftLookupBatch == null && rightLookupBatch == null) {
return null;
}
return new UnionLookupBatch(leftLookupBatch, rightLookupBatch);
}
public Session getSession() {
return createSession;
}
......@@ -221,7 +265,7 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
if (query == null) {
query = (Query) createSession.prepare(querySQL, true);
}
if (!(query instanceof SelectUnion)) {
if (!query.isUnion()) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL");
}
......@@ -454,4 +498,41 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
return recursive;
}
/**
* Lookup batch for unions.
*/
private static final class UnionLookupBatch implements IndexLookupBatch {
private final IndexLookupBatch left;
private final IndexLookupBatch right;
private UnionLookupBatch(IndexLookupBatch left, IndexLookupBatch right) {
this.left = left;
this.right = right;
}
@Override
public void addSearchRows(SearchRow first, SearchRow last) {
assert !left.isBatchFull();
assert !right.isBatchFull();
left.addSearchRows(first, last);
right.addSearchRows(first, last);
}
@Override
public boolean isBatchFull() {
return left.isBatchFull() || right.isBatchFull();
}
@Override
public List<Future<Cursor>> find() {
// TODO Auto-generated method stub
return null;
}
@Override
public void reset() {
left.reset();
right.reset();
}
}
}
......@@ -83,6 +83,8 @@ public final class JoinBatch {
}
/**
* Check if the index at the given table filter really supports batching in this query.
*
* @param joinFilterId joined table filter id
* @return {@code true} if index really supports batching in this query
*/
......@@ -90,6 +92,16 @@ public final class JoinBatch {
return filters[joinFilterId].isBatched();
}
/**
* Get the lookup batch for the given table filter.
*
* @param joinFilterId joined table filter id
* @return lookup batch
*/
public IndexLookupBatch getLookupBatch(int joinFilterId) {
return filters[joinFilterId].lookupBatch;
}
/**
* Reset state of this batch.
*/
......
......@@ -339,6 +339,23 @@ public class TableFilter implements ColumnResolver {
foundOne = false;
}
private boolean isAlwaysTopTableFilter(int id) {
if (id != 0) {
return false;
}
// check if we are at the top table filters all the way up
SubQueryInfo info = session.getSubQueryInfo();
for (;;) {
if (info == null) {
return true;
}
if (info.getFilter() != 0) {
return false;
}
info = info.getUpper();
}
}
/**
* Attempt to initialize batched join.
*
......@@ -351,8 +368,7 @@ public class TableFilter implements ColumnResolver {
batch = join.prepareBatch(id + 1);
}
IndexLookupBatch lookupBatch = null;
if (batch == null && select != null && id != 0) {
// TODO session.getSubQueryInfo() instead of id != 0 + use upper level sub-query info
if (batch == null && select != null && !isAlwaysTopTableFilter(id)) {
lookupBatch = index.createLookupBatch(this);
if (lookupBatch != null) {
batch = new JoinBatch(id + 1, join);
......@@ -362,12 +378,11 @@ public class TableFilter implements ColumnResolver {
if (nestedJoin != null) {
throw DbException.getUnsupportedException("nested join with batched index");
}
if (lookupBatch == null && id != 0) {
// TODO session.getSubQueryInfo() instead of id != 0 + use upper level sub-query info
lookupBatch = index.createLookupBatch(this);
}
joinBatch = batch;
joinFilterId = id;
if (lookupBatch == null && !isAlwaysTopTableFilter(id)) {
lookupBatch = index.createLookupBatch(this);
}
batch.register(this, lookupBatch);
}
return batch;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论