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

Experimental feature to support nested joins.

上级 1a47715d
......@@ -866,7 +866,12 @@ public class Select extends Query {
if (on != null) {
if (!on.isEverything(ExpressionVisitor.EVALUATABLE)) {
if (SysProperties.NESTED_JOINS) {
int testCanSupport;
f.removeJoinCondition();
// need to check that all added are bound to a table
on = on.optimize(session);
if (!f.isJoinOuter() && !f.isJoinOuterIndirect()) {
addCondition(on);
}
} else {
if (f.isJoinOuter()) {
// this will check if all columns exist - it may or may not throw an exception
......@@ -874,13 +879,13 @@ public class Select extends Query {
// it is not supported even if the columns exist
throw DbException.get(ErrorCode.UNSUPPORTED_OUTER_JOIN_CONDITION_1, on.getSQL());
}
}
f.removeJoinCondition();
// need to check that all added are bound to a table
on = on.optimize(session);
addCondition(on);
}
}
}
on = f.getFilterCondition();
if (on != null) {
if (!on.isEverything(ExpressionVisitor.EVALUATABLE)) {
......
......@@ -246,6 +246,9 @@ public class ExpressionColumn extends Expression {
// or if this columns belongs to a 'higher level' query and is
// therefore just a parameter
if (SysProperties.NESTED_JOINS) {
if (visitor.getQueryLevel() < this.queryLevel) {
return true;
}
if (getTableFilter() == null) {
return false;
}
......
......@@ -34,10 +34,10 @@ import org.h2.value.Value;
*/
public class TableFilter implements ColumnResolver {
private static final int BEFORE_FIRST = 0, FOUND = 1, AFTER_LAST = 2, NULL_ROW = 3;
protected Session session;
private final Table table;
private final Select select;
private String alias;
private Session session;
private Index index;
private int scanCount;
private boolean evaluatable;
......@@ -78,10 +78,15 @@ public class TableFilter implements ColumnResolver {
private TableFilter join;
/**
* Whether this table is an outer join.
* Whether this is an outer join.
*/
private boolean joinOuter;
/**
* Whether this is a direct or indirect (nested) outer join
*/
protected boolean joinOuterIndirect;
/**
* The nested joined table (if there is one).
*/
......@@ -505,6 +510,13 @@ public class TableFilter implements ColumnResolver {
}
nestedJoin = filter;
filter.joinOuter = outer;
if (outer) {
visit(new TableFilterVisitor() {
public void accept(TableFilter f) {
f.joinOuterIndirect = true;
}
});
}
if (on != null) {
filter.mapAndAddFilter(on);
}
......@@ -540,6 +552,10 @@ public class TableFilter implements ColumnResolver {
on.mapColumns(this, 0);
addFilterCondition(on, true);
on.createIndexConditions(session, this);
if (nestedJoin != null) {
on.mapColumns(nestedJoin, 0);
on.createIndexConditions(session, nestedJoin);
}
if (join != null) {
join.mapAndAddFilter(on);
}
......@@ -550,7 +566,7 @@ public class TableFilter implements ColumnResolver {
}
/**
* Check if this is an outer joined table.
* Whether this is an outer joined table.
*
* @return true if it is
*/
......@@ -558,6 +574,15 @@ public class TableFilter implements ColumnResolver {
return joinOuter;
}
/**
* Whether this is indirectly an outer joined table (nested within an inner join).
*
* @return true if it is
*/
public boolean isJoinOuterIndirect() {
return joinOuterIndirect;
}
/**
* Get the query execution plan text to use for this table filter.
*
......@@ -731,7 +756,7 @@ public class TableFilter implements ColumnResolver {
* @param b the new flag
*/
public void setEvaluatable(TableFilter filter, boolean b) {
setEvaluatable(b);
filter.setEvaluatable(b);
if (filterCondition != null) {
filterCondition.setEvaluatable(filter, b);
}
......
......@@ -305,6 +305,8 @@ java org.h2.test.TestAll timer
// System.setProperty("h2.lobInDatabase", "true");
// System.setProperty("h2.analyzeAuto", "100");
// System.setProperty("h2.nestedJoins", "true");
// System.setProperty("h2.optimizeOr", "true");
// System.setProperty("h2.dropRestrict", "true");
int speedup;
// System.setProperty("h2.syncMethod", "");
......
......@@ -37,7 +37,7 @@ public class TestNestedJoins extends TestBase {
public static void main(String... a) throws Exception {
System.setProperty("h2.nestedJoins", "true");
TestBase test = TestBase.createCaller().init();
test.config.traceTest = true;
// test.config.traceTest = true;
test.test();
}
......@@ -62,17 +62,15 @@ public class TestNestedJoins extends TestBase {
} catch (Exception e) {
// database not installed - ok
}
// Derby doesn't work currently
deleteDerby();
try {
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection c2 = DriverManager.getConnection("jdbc:derby:" + getBaseDir() + "/derby/test;create=true", "sa", "sa");
dbs.add(c2.createStatement());
} catch (Exception e) {
// database not installed - ok
}
// if (dbs.size() == 0) {
// return;
// deleteDerby();
// try {
// Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
// Connection c2 = DriverManager.getConnection("jdbc:derby:" + getBaseDir() + "/derby/test;create=true", "sa", "sa");
// dbs.add(c2.createStatement());
// } catch (Exception e) {
// // database not installed - ok
// }
String shortest = null;
Throwable shortestEx = null;
......@@ -121,12 +119,11 @@ public class TestNestedJoins extends TestBase {
execute(sql);
} catch (Throwable e) {
if (e instanceof SQLException) {
SQLException se = (SQLException) e;
trace(sql);
int todoFail;
int test;
System.out.println(se);
System.out.println(" " + sql);
fail(sql);
// SQLException se = (SQLException) e;
// System.out.println(se);
// System.out.println(" " + sql);
}
if (e != null) {
if (shortest == null || sql.length() < shortest.length()) {
......@@ -243,6 +240,18 @@ int test;
ResultSet rs;
String sql;
/*
create table test(id int primary key);
explain select * from test a left outer join (test c) on a.id = c.id;
-- expected: uses the primary key index
*/
stat.execute("create table test(id int primary key)");
rs = stat.executeQuery("explain select * from test a left outer join (test c) on a.id = c.id");
assertTrue(rs.next());
sql = rs.getString(1);
assertTrue(sql.indexOf("PRIMARY_KEY") >= 0);
stat.execute("drop table test");
/*
create table t1(a int, b int);
create table t2(a int, b int);
......@@ -315,6 +324,18 @@ int test;
assertFalse(rs.next());
stat.execute("drop table a, b, c");
/*
drop table a, b, c;
create table a(x int);
create table b(x int);
create table c(x int, y int);
insert into a values(1), (2);
insert into b values(3);
insert into c values(1, 3);
insert into c values(4, 5);
explain select * from a left outer join (b left outer join c on b.x = c.y) on a.x = c.x;
select * from a left outer join (b left outer join c on b.x = c.y) on a.x = c.x;
*/
stat.execute("create table a(x int)");
stat.execute("create table b(x int)");
stat.execute("create table c(x int, y int)");
......@@ -490,7 +511,6 @@ int test;
r.setSkipRemarks(true);
sql = r.readStatement();
sql = sql.replaceAll("\\n", " ");
// sql = sql.replaceAll("\\/\\*.*\\*\\/", "");
while (sql.indexOf(" ") >= 0) {
sql = sql.replaceAll(" ", " ");
}
......
......@@ -885,9 +885,6 @@ select * from ((test d1 inner join test d2 on d1.id = d2.id) inner join test d3
> -- -- -- --
> rows: 0
select * from dual a left join dual b on b.x=(select max(x) from dual);
> exception
drop table test;
> ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论