提交 b4f18991 authored 作者: Thomas Mueller's avatar Thomas Mueller

Recursive queries with many rows could throw an IndexOutOfBoundsException.

上级 56f4e91a
...@@ -18,7 +18,8 @@ Change Log ...@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1> <h1>Change Log</h1>
<h2>Next Version (unreleased)</h2> <h2>Next Version (unreleased)</h2>
<ul><li>The auto-server mode can't be combined with an in-memory database. <ul><li>Recursive queries with many rows could throw an IndexOutOfBoundsException.
</li><li>The auto-server mode can't be combined with an in-memory database.
This invalid combination wasn't detected so far. This invalid combination wasn't detected so far.
Now trying to open a database in this way fails. Now trying to open a database in this way fails.
</li><li>Improved performance for reading and writing date and time values. </li><li>Improved performance for reading and writing date and time values.
......
...@@ -157,10 +157,10 @@ public class ViewIndex extends BaseIndex { ...@@ -157,10 +157,10 @@ public class ViewIndex extends BaseIndex {
public Cursor find(Session session, SearchRow first, SearchRow last) { public Cursor find(Session session, SearchRow first, SearchRow last) {
if (recursive) { if (recursive) {
if (view.getRecursiveResult() != null) { ResultInterface recResult = view.getRecursiveResult(session);
ResultInterface r = view.getRecursiveResult(); if (recResult != null) {
r.reset(); recResult.reset();
return new ViewCursor(table, r); return new ViewCursor(table, recResult);
} }
if (query == null) { if (query == null) {
query = (Query) createSession.prepare(querySQL, true); query = (Query) createSession.prepare(querySQL, true);
...@@ -174,14 +174,14 @@ public class ViewIndex extends BaseIndex { ...@@ -174,14 +174,14 @@ public class ViewIndex extends BaseIndex {
throw DbException.get(ErrorCode.SYNTAX_ERROR_2, "recursive queries without UNION ALL"); throw DbException.get(ErrorCode.SYNTAX_ERROR_2, "recursive queries without UNION ALL");
} }
Query left = union.getLeft(); Query left = union.getLeft();
ResultInterface r = left.query(0); LocalResult r = left.query(0);
LocalResult result = union.getEmptyResult(); LocalResult result = union.getEmptyResult();
while (r.next()) { while (r.next()) {
result.addRow(r.currentRow()); result.addRow(r.currentRow());
} }
Query right = union.getRight(); Query right = union.getRight();
r.reset(); r.reset();
view.setRecursiveResult(r); view.setRecursiveResult(r, session);
while (true) { while (true) {
r = right.query(0); r = right.query(0);
if (r.getRowCount() == 0) { if (r.getRowCount() == 0) {
...@@ -191,7 +191,7 @@ public class ViewIndex extends BaseIndex { ...@@ -191,7 +191,7 @@ public class ViewIndex extends BaseIndex {
result.addRow(r.currentRow()); result.addRow(r.currentRow());
} }
r.reset(); r.reset();
view.setRecursiveResult(r); view.setRecursiveResult(r, session);
} }
return new ViewCursor(table, result); return new ViewCursor(table, result);
} }
......
...@@ -20,6 +20,7 @@ import org.h2.index.Index; ...@@ -20,6 +20,7 @@ import org.h2.index.Index;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.index.ViewIndex; import org.h2.index.ViewIndex;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.result.LocalResult;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.schema.Schema; import org.h2.schema.Schema;
...@@ -50,7 +51,7 @@ public class TableView extends Table { ...@@ -50,7 +51,7 @@ public class TableView extends Table {
private long maxDataModificationId; private long maxDataModificationId;
private User owner; private User owner;
private Query topQuery; private Query topQuery;
private ResultInterface recursiveResult; private LocalResult recursiveResult;
private boolean tableExpression; private boolean tableExpression;
public TableView(Schema schema, int id, String name, String querySQL, ArrayList<Parameter> params, String[] columnNames, public TableView(Schema schema, int id, String name, String querySQL, ArrayList<Parameter> params, String[] columnNames,
...@@ -443,12 +444,12 @@ public class TableView extends Table { ...@@ -443,12 +444,12 @@ public class TableView extends Table {
return viewQuery.isEverything(ExpressionVisitor.DETERMINISTIC_VISITOR); return viewQuery.isEverything(ExpressionVisitor.DETERMINISTIC_VISITOR);
} }
public void setRecursiveResult(ResultInterface recursiveResult) { public void setRecursiveResult(LocalResult value, Session session) {
this.recursiveResult = recursiveResult; this.recursiveResult = value.createShallowCopy(session);
} }
public ResultInterface getRecursiveResult() { public ResultInterface getRecursiveResult(Session session) {
return recursiveResult; return recursiveResult == null ? null : recursiveResult.createShallowCopy(session);
} }
public void setTableExpression(boolean tableExpression) { public void setTableExpression(boolean tableExpression) {
......
...@@ -27,6 +27,34 @@ public class TestRecursiveQueries extends TestBase { ...@@ -27,6 +27,34 @@ public class TestRecursiveQueries extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
testWrongLinkLargeResult();
testSimple();
}
private void testWrongLinkLargeResult() throws Exception {
deleteDb("recursiveQueries");
Connection conn = getConnection("recursiveQueries");
Statement stat;
stat = conn.createStatement();
stat.execute("create table test(parent varchar(255), child varchar(255))");
stat.execute("insert into test values('/', 'a'), ('a', 'b1'), ('a', 'b2'), ('a', 'c'), ('c', 'd1'), ('c', 'd2')");
// stat.execute("with recursive rec_test(depth, parent, child) as (" +
// "select 0, parent, child from test where parent = '/' " +
// "union all " +
// "select depth+1, r.parent, r.child from test i join rec_test r " +
// "on (i.parent = r.child) where depth<9 " +
// ") select * from rec_test");
stat.execute("with recursive rec_test(depth, parent, child) as ( "+
"select 0, parent, child from test where parent = '/' "+
"union all "+
"select depth+1, i.parent, i.child from test i join rec_test r "+
"on (r.child = i.parent) where depth<10 "+
") select * from rec_test");
conn.close();
deleteDb("recursiveQueries");
}
private void testSimple() throws Exception {
deleteDb("recursiveQueries"); deleteDb("recursiveQueries");
Connection conn = getConnection("recursiveQueries"); Connection conn = getConnection("recursiveQueries");
Statement stat; Statement stat;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论