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

wip

上级 1e9b6d64
......@@ -6,8 +6,6 @@
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;
......@@ -103,12 +101,8 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
// we do not support batching for recursive queries
return null;
}
IndexLookupBatch lookupBatch = query.isUnion() ?
createLookupBatchUnion((SelectUnion) query) :
createLookupBatchSimple((Select) query);
// TODO not initialize index cursor on the top table filter but work as usual batching
// TODO return wrapper which goes through all the joins an collects all the rows
return null;
// currently do not support unions
return query.isUnion() ? null : createLookupBatchSimple((Select) query);
}
private IndexLookupBatch createLookupBatchSimple(Select select) {
......@@ -119,30 +113,7 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
// our sub-query itself is not batched, will run usual way
return null;
}
// TODO wrap the join batch into lookup batch
return null;
}
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) {
if (rightLookupBatch == null) {
return null;
}
leftLookupBatch = null; // TODO
} else if (rightLookupBatch == null) {
rightLookupBatch = null; // TODO
}
return new UnionLookupBatch(leftLookupBatch, rightLookupBatch);
return joinBatch.asViewIndexLookupBatch(this);
}
public Session getSession() {
......@@ -263,57 +234,60 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
return (Query) p;
}
private Cursor find(Session session, SearchRow first, SearchRow last,
private Cursor findRecursive(Session session, SearchRow first, SearchRow last,
SearchRow intersection) {
if (recursive) {
LocalResult recResult = view.getRecursiveResult();
if (recResult != null) {
recResult.reset();
return new ViewCursor(this, recResult, first, last);
}
if (query == null) {
query = (Query) createSession.prepare(querySQL, true);
}
if (!query.isUnion()) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL");
}
SelectUnion union = (SelectUnion) query;
if (union.getUnionType() != SelectUnion.UNION_ALL) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL");
assert recursive;
LocalResult recResult = view.getRecursiveResult();
if (recResult != null) {
recResult.reset();
return new ViewCursor(this, recResult, first, last);
}
if (query == null) {
query = (Query) createSession.prepare(querySQL, true);
}
if (!query.isUnion()) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL");
}
SelectUnion union = (SelectUnion) query;
if (union.getUnionType() != SelectUnion.UNION_ALL) {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2,
"recursive queries without UNION ALL");
}
Query left = union.getLeft();
// to ensure the last result is not closed
left.disableCache();
LocalResult r = left.query(0);
LocalResult result = union.getEmptyResult();
// ensure it is not written to disk,
// because it is not closed normally
result.setMaxMemoryRows(Integer.MAX_VALUE);
while (r.next()) {
result.addRow(r.currentRow());
}
Query right = union.getRight();
r.reset();
view.setRecursiveResult(r);
// to ensure the last result is not closed
right.disableCache();
while (true) {
r = right.query(0);
if (r.getRowCount() == 0) {
break;
}
Query left = union.getLeft();
// to ensure the last result is not closed
left.disableCache();
LocalResult r = left.query(0);
LocalResult result = union.getEmptyResult();
// ensure it is not written to disk,
// because it is not closed normally
result.setMaxMemoryRows(Integer.MAX_VALUE);
while (r.next()) {
result.addRow(r.currentRow());
}
Query right = union.getRight();
r.reset();
view.setRecursiveResult(r);
// to ensure the last result is not closed
right.disableCache();
while (true) {
r = right.query(0);
if (r.getRowCount() == 0) {
break;
}
while (r.next()) {
result.addRow(r.currentRow());
}
r.reset();
view.setRecursiveResult(r);
}
view.setRecursiveResult(null);
result.done();
return new ViewCursor(this, result, first, last);
}
view.setRecursiveResult(null);
result.done();
return new ViewCursor(this, result, first, last);
}
public void setupQueryParameters(Session session, SearchRow first, SearchRow last,
SearchRow intersection) {
ArrayList<Parameter> paramList = query.getParameters();
if (originalParameters != null) {
for (int i = 0, size = originalParameters.size(); i < size; i++) {
......@@ -350,6 +324,14 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
setParameter(paramList, idx++, intersection.getValue(i));
}
}
}
private Cursor find(Session session, SearchRow first, SearchRow last,
SearchRow intersection) {
if (recursive) {
return findRecursive(session, first, last, intersection);
}
setupQueryParameters(session, first, last, intersection);
LocalResult result = query.query(0);
return new ViewCursor(this, result, first, last);
}
......@@ -506,42 +488,4 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
public boolean isRecursive() {
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();
}
}
}
......@@ -6,6 +6,7 @@
package org.h2.table;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
......@@ -13,10 +14,12 @@ import java.util.concurrent.Future;
import org.h2.index.Cursor;
import org.h2.index.IndexCursor;
import org.h2.index.IndexLookupBatch;
import org.h2.index.ViewIndex;
import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.util.DoneFuture;
import org.h2.util.New;
import org.h2.value.Value;
import org.h2.value.ValueLong;
......@@ -28,7 +31,6 @@ import org.h2.value.ValueLong;
* @author Sergi Vladykin
*/
public final class JoinBatch {
private static final Cursor EMPTY_CURSOR = new Cursor() {
@Override
public boolean previous() {
......@@ -54,7 +56,11 @@ public final class JoinBatch {
public String toString() {
return "EMPTY_CURSOR";
}
};
};
private static final Future<Cursor> PLACEHOLDER = new DoneFuture<Cursor>(null);
private ViewIndexLookupBatch lookupBatchWrapper;
private JoinFilter[] filters;
private JoinFilter top;
......@@ -148,14 +154,16 @@ public final class JoinBatch {
}
private void start() {
// TODO if filters[0].isBatched() then use batching instead of top.filter.getIndexCursor()
// initialize current row
current = new JoinRow(new Object[filters.length]);
current.updateRow(top.id, top.filter.getIndexCursor(), JoinRow.S_NULL, JoinRow.S_CURSOR);
// initialize top cursor
top.filter.getIndexCursor().find(top.filter.getSession(), top.filter.getIndexConditions());
if (lookupBatchWrapper == null) {
current.updateRow(top.id, top.filter.getIndexCursor(), JoinRow.S_NULL, JoinRow.S_CURSOR);
// initialize top cursor
top.filter.getIndexCursor().find(top.filter.getSession(), top.filter.getIndexConditions());
} else {
// we are sub-query and joined to upper level query
// TODO setup
}
// we need fake first row because batchedNext always will move to the next row
JoinRow fake = new JoinRow(null);
fake.next = current;
......@@ -239,7 +247,7 @@ public final class JoinBatch {
current = join.find(current);
}
if (current.row(join.id) != null) {
// either find called or outer join with null row
// either find called or outer join with null-row
jfId = join.id;
continue;
}
......@@ -340,13 +348,23 @@ public final class JoinBatch {
}
}
/**
* @return Adapter to allow joining to this batch in sub-queries.
*/
public IndexLookupBatch asViewIndexLookupBatch(ViewIndex viewIndex) {
if (lookupBatchWrapper == null) {
lookupBatchWrapper = new ViewIndexLookupBatch(viewIndex);
}
return lookupBatchWrapper;
}
@Override
public String toString() {
return "JoinBatch->\nprev->" + (current == null ? null : current.prev) +
"\ncurr->" + current +
"\nnext->" + (current == null ? null : current.next);
}
/**
* Table filter participating in batched join.
*/
......@@ -404,6 +422,10 @@ public final class JoinBatch {
return true;
}
private List<Future<Cursor>> find() {
return lookupBatch.find();
}
private JoinRow find(JoinRow current) {
assert current != null;
......@@ -655,5 +677,70 @@ public final class JoinBatch {
return 1;
}
}
/**
* Lookup batch over this join batch for a sub-query or view.
*/
private final class ViewIndexLookupBatch implements IndexLookupBatch {
private final ViewIndex viewIndex;
private final ArrayList<Future<Cursor>> result = New.arrayList();
private boolean findCalled;
private ViewIndexLookupBatch(ViewIndex viewIndex) {
this.viewIndex = viewIndex;
}
@Override
public void addSearchRows(SearchRow first, SearchRow last) {
if (findCalled) {
result.clear();
findCalled = false;
}
viewIndex.setupQueryParameters(viewIndex.getSession(), first, last, null);
if (top.collectSearchRows()) {
result.add(PLACEHOLDER);
if (top.isBatchFull()) {
// TODO
}
} else {
result.add(null);
}
}
@Override
public boolean isBatchFull() {
assert !findCalled;
return top.isBatchFull();
}
@Override
public List<Future<Cursor>> find() {
JoinBatch jb = JoinBatch.this;
List<Future<Cursor>> topCursors = top.find();
for (int i = 0; i < topCursors.size(); i++) {
// jb.setCursor
while (jb.next()) {
// collect result
}
}
findCalled = true;
return result;
}
@Override
public void reset() {
findCalled = false;
result.clear();
JoinBatch.this.reset();
}
}
/**
* State of the
*/
enum State {
}
}
......@@ -371,7 +371,10 @@ public class TableFilter implements ColumnResolver {
jb = join.prepareBatch(id + 1);
}
IndexLookupBatch lookupBatch = null;
// TODO review the !isAlwaysTopTableFilter condition
// the globally top table filter does not need batching, if isAlwaysTopTableFilter is false
// then we either not a top table filter or top table filter in a sub-query which is not
// top in outer query, thus we need to enable batching here to allow outer query run batched
// join against this sub-query
if (jb == null && select != null && !isAlwaysTopTableFilter(id)) {
lookupBatch = index.createLookupBatch(this);
if (lookupBatch != null) {
......@@ -384,8 +387,13 @@ public class TableFilter implements ColumnResolver {
}
joinBatch = jb;
joinFilterId = id;
// TODO review the !isAlwaysTopTableFilter condition
// for globally top table filter we don't need to create lookup batch
// currently it will not be used, probably later on it will make sense
// to create it to better support X IN (...) conditions, but this needs
// to be implemented separately
if (lookupBatch == null && !isAlwaysTopTableFilter(id)) {
// index.createLookupBatch will be called only once because jb can be created only if
// lookupBatch is not null from the first call above
lookupBatch = index.createLookupBatch(this);
}
jb.register(this, lookupBatch);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论