Unverified 提交 9d28c9f6 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #907 from katzyn/join

Nest joins only if required and fix some issues with complex joins
...@@ -1369,8 +1369,7 @@ public class Parser { ...@@ -1369,8 +1369,7 @@ public class Parser {
} else { } else {
TableFilter top; TableFilter top;
top = readTableFilter(); top = readTableFilter();
top = readJoin(top, false); top = readJoin(top);
top = getNested(top);
read(")"); read(")");
alias = readFromAlias(null); alias = readFromAlias(null);
if (alias != null) { if (alias != null) {
...@@ -1717,8 +1716,7 @@ public class Parser { ...@@ -1717,8 +1716,7 @@ public class Parser {
return command; return command;
} }
private TableFilter readJoin(TableFilter top, boolean nested) { private TableFilter readJoin(TableFilter top) {
boolean joined = false;
TableFilter last = top; TableFilter last = top;
while (true) { while (true) {
TableFilter join; TableFilter join;
...@@ -1727,47 +1725,46 @@ public class Parser { ...@@ -1727,47 +1725,46 @@ public class Parser {
read("JOIN"); read("JOIN");
// the right hand side is the 'inner' table usually // the right hand side is the 'inner' table usually
join = readTableFilter(); join = readTableFilter();
join = readJoin(join, nested); join = readJoin(join);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf("ON")) {
on = readExpression(); on = readExpression();
} }
top = getNested(top); addJoin(join, top, true, on);
join.addJoin(top, true, on);
top = join; top = join;
} else if (readIf("LEFT")) { } else if (readIf("LEFT")) {
readIf("OUTER"); readIf("OUTER");
read("JOIN"); read("JOIN");
join = readTableFilter(); join = readTableFilter();
join = readJoin(join, true); join = readJoin(join);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf("ON")) {
on = readExpression(); on = readExpression();
} }
top.addJoin(join, true, on); addJoin(top, join, true, on);
} else if (readIf("FULL")) { } else if (readIf("FULL")) {
throw getSyntaxError(); throw getSyntaxError();
} else if (readIf("INNER")) { } else if (readIf("INNER")) {
read("JOIN"); read("JOIN");
join = readTableFilter(); join = readTableFilter();
top = readJoin(top, false); top = readJoin(top);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf("ON")) {
on = readExpression(); on = readExpression();
} }
top.addJoin(join, false, on); addJoin(top, join, false, on);
} else if (readIf("JOIN")) { } else if (readIf("JOIN")) {
join = readTableFilter(); join = readTableFilter();
top = readJoin(top, false); top = readJoin(top);
Expression on = null; Expression on = null;
if (readIf("ON")) { if (readIf("ON")) {
on = readExpression(); on = readExpression();
} }
top.addJoin(join, false, on); addJoin(top, join, false, on);
} else if (readIf("CROSS")) { } else if (readIf("CROSS")) {
read("JOIN"); read("JOIN");
join = readTableFilter(); join = readTableFilter();
top.addJoin(join, false, null); addJoin(top, join, false, null);
} else if (readIf("NATURAL")) { } else if (readIf("NATURAL")) {
read("JOIN"); read("JOIN");
join = readTableFilter(); join = readTableFilter();
...@@ -1799,26 +1796,35 @@ public class Parser { ...@@ -1799,26 +1796,35 @@ public class Parser {
} }
} }
} }
top.addJoin(join, false, on); addJoin(top, join, false, on);
} else { } else {
break; break;
} }
joined = true;
last = join; last = join;
} }
if (nested && joined) {
top = getNested(top);
}
return top; return top;
} }
private TableFilter getNested(TableFilter n) { /**
String joinTable = Constants.PREFIX_JOIN + parseIndex; * Add one join to another. This method creates nested join between them if
TableFilter top = new TableFilter(session, getDualTable(true), * required.
joinTable, rightsChecked, currentSelect, n.getOrderInFrom(), *
null); * @param top parent join
top.setNestedJoin(n); * @param join child join
return top; * @param outer if child join is an outer join
* @param on the join condition
* @see TableFilter#addJoin(TableFilter, boolean, Expression)
*/
private void addJoin(TableFilter top, TableFilter join, boolean outer, Expression on) {
if (join.getJoin() != null) {
String joinTable = Constants.PREFIX_JOIN + parseIndex;
TableFilter n = new TableFilter(session, getDualTable(true),
joinTable, rightsChecked, currentSelect, join.getOrderInFrom(),
null);
n.setNestedJoin(join);
join = n;
}
top.addJoin(join, outer, on);
} }
private Prepared parseExecute() { private Prepared parseExecute() {
...@@ -2149,7 +2155,7 @@ public class Parser { ...@@ -2149,7 +2155,7 @@ public class Parser {
} }
private void parseJoinTableFilter(TableFilter top, final Select command) { private void parseJoinTableFilter(TableFilter top, final Select command) {
top = readJoin(top, false); top = readJoin(top);
command.addTableFilter(top, true); command.addTableFilter(top, true);
boolean isOuter = false; boolean isOuter = false;
while (true) { while (true) {
......
...@@ -401,7 +401,7 @@ public class IndexCondition { ...@@ -401,7 +401,7 @@ public class IndexCondition {
return "column=" + column + return "column=" + column +
", compareType=" + compareTypeToString(compareType) + ", compareType=" + compareTypeToString(compareType) +
", expression=" + expression + ", expression=" + expression +
", expressionList=" + expressionList.toString() + ", expressionList=" + expressionList +
", expressionQuery=" + expressionQuery; ", expressionQuery=" + expressionQuery;
} }
......
...@@ -168,7 +168,6 @@ public class ViewIndex extends BaseIndex implements SpatialIndex { ...@@ -168,7 +168,6 @@ public class ViewIndex extends BaseIndex implements SpatialIndex {
private static Query prepareSubQuery(String sql, Session session, int[] masks, private static Query prepareSubQuery(String sql, Session session, int[] masks,
TableFilter[] filters, int filter, SortOrder sortOrder) { TableFilter[] filters, int filter, SortOrder sortOrder) {
assert filters != null;
Prepared p; Prepared p;
session.pushSubQueryInfo(masks, filters, filter, sortOrder); session.pushSubQueryInfo(masks, filters, filter, sortOrder);
try { try {
......
...@@ -265,15 +265,34 @@ public class TableFilter implements ColumnResolver { ...@@ -265,15 +265,34 @@ public class TableFilter implements ColumnResolver {
if (nestedJoin != null) { if (nestedJoin != null) {
if (item.getNestedJoinPlan() != null) { if (item.getNestedJoinPlan() != null) {
nestedJoin.setPlanItem(item.getNestedJoinPlan()); nestedJoin.setPlanItem(item.getNestedJoinPlan());
} else {
nestedJoin.setScanIndexes();
} }
} }
if (join != null) { if (join != null) {
if (item.getJoinPlan() != null) { if (item.getJoinPlan() != null) {
join.setPlanItem(item.getJoinPlan()); join.setPlanItem(item.getJoinPlan());
} else {
join.setScanIndexes();
} }
} }
} }
/**
* Set all missing indexes to scan indexes recursively.
*/
private void setScanIndexes() {
if (index == null) {
setIndex(table.getScanIndex(session));
}
if (join != null) {
join.setScanIndexes();
}
if (nestedJoin != null) {
nestedJoin.setScanIndexes();
}
}
/** /**
* Prepare reading rows. This method will remove all index conditions that * Prepare reading rows. This method will remove all index conditions that
* can not be used, and optimize the conditions. * can not be used, and optimize the conditions.
......
...@@ -103,6 +103,21 @@ select a.i from t1 a inner join (select a.i from t2 a inner join (select i from ...@@ -103,6 +103,21 @@ select a.i from t1 a inner join (select a.i from t2 a inner join (select i from
> - > -
> rows: 0 > rows: 0
insert into t1 values (1);
> update count: 1
insert into t2 values (1);
> update count: 1
insert into t3 values (1);
> update count: 1
select a.i from t1 a inner join (select a.i from t2 a inner join (select i from t3) b on a.i=b.i) b on a.i=b.i;
> I
> -
> 1
> rows: 1
drop table t1, t2, t3; drop table t1, t2, t3;
> ok > ok
...@@ -747,3 +762,32 @@ DROP TABLE B; ...@@ -747,3 +762,32 @@ DROP TABLE B;
DROP TABLE C; DROP TABLE C;
> ok > ok
CREATE TABLE T1(X1 INT);
CREATE TABLE T2(X2 INT);
CREATE TABLE T3(X3 INT);
CREATE TABLE T4(X4 INT);
CREATE TABLE T5(X5 INT);
INSERT INTO T1 VALUES (1);
INSERT INTO T1 VALUES (NULL);
INSERT INTO T2 VALUES (1);
INSERT INTO T2 VALUES (NULL);
INSERT INTO T3 VALUES (1);
INSERT INTO T3 VALUES (NULL);
INSERT INTO T4 VALUES (1);
INSERT INTO T4 VALUES (NULL);
INSERT INTO T5 VALUES (1);
INSERT INTO T5 VALUES (NULL);
SELECT T1.X1, T2.X2, T3.X3, T4.X4, T5.X5 FROM (
T1 INNER JOIN (
T2 LEFT OUTER JOIN (
T3 INNER JOIN T4 ON T3.X3 = T4.X4
) ON T2.X2 = T4.X4
) ON T1.X1 = T2.X2
) INNER JOIN T5 ON T2.X2 = T5.X5;
> X1 X2 X3 X4 X5
> -- -- -- -- --
> 1 1 1 1 1
> rows: 1
...@@ -380,7 +380,7 @@ public class TestNestedJoins extends TestBase { ...@@ -380,7 +380,7 @@ public class TestNestedJoins extends TestBase {
assertTrue(rs.next()); assertTrue(rs.next());
sql = cleanRemarks(rs.getString(1)); sql = cleanRemarks(rs.getString(1));
assertEquals("SELECT DISTINCT T1.A, T2.A, T3.A FROM PUBLIC.T2 " + assertEquals("SELECT DISTINCT T1.A, T2.A, T3.A FROM PUBLIC.T2 " +
"LEFT OUTER JOIN ( PUBLIC.T3 LEFT OUTER JOIN ( PUBLIC.T1 ) " + "LEFT OUTER JOIN ( PUBLIC.T3 LEFT OUTER JOIN PUBLIC.T1 " +
"ON T1.B = T3.A ) ON T2.B = T1.A", sql); "ON T1.B = T3.A ) ON T2.B = T1.A", sql);
rs = stat.executeQuery("select distinct t1.a, t2.a, t3.a from t1 " + rs = stat.executeQuery("select distinct t1.a, t2.a, t3.a from t1 " +
"right outer join t3 on t1.b=t3.a " + "right outer join t3 on t1.b=t3.a " +
......
...@@ -136,7 +136,7 @@ public class TestOuterJoins extends TestBase { ...@@ -136,7 +136,7 @@ public class TestOuterJoins extends TestBase {
s.getConnection().close(); s.getConnection().close();
} }
deleteDerby(); deleteDerby();
deleteDb("nestedJoins"); deleteDb("outerJoins");
} }
private void deleteDerby() { private void deleteDerby() {
...@@ -289,7 +289,7 @@ public class TestOuterJoins extends TestBase { ...@@ -289,7 +289,7 @@ public class TestOuterJoins extends TestBase {
private void testCases() throws Exception { private void testCases() throws Exception {
Connection conn = getConnection("nestedJoins"); Connection conn = getConnection("outerJoins");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
ResultSet rs; ResultSet rs;
String sql; String sql;
...@@ -334,7 +334,7 @@ public class TestOuterJoins extends TestBase { ...@@ -334,7 +334,7 @@ public class TestOuterJoins extends TestBase {
sql = cleanRemarks(rs.getString(1)); sql = cleanRemarks(rs.getString(1));
assertEquals("SELECT DISTINCT T1.A, T2.A, T3.A FROM PUBLIC.T2 " + assertEquals("SELECT DISTINCT T1.A, T2.A, T3.A FROM PUBLIC.T2 " +
"LEFT OUTER JOIN ( PUBLIC.T3 " + "LEFT OUTER JOIN ( PUBLIC.T3 " +
"LEFT OUTER JOIN ( PUBLIC.T1 ) ON T1.B = T3.A ) " + "LEFT OUTER JOIN PUBLIC.T1 ON T1.B = T3.A ) " +
"ON T2.B = T1.A", sql); "ON T2.B = T1.A", sql);
rs = stat.executeQuery("select distinct t1.a, t2.a, t3.a from t1 " + rs = stat.executeQuery("select distinct t1.a, t2.a, t3.a from t1 " +
"right outer join t3 on t1.b=t3.a right outer join t2 on t2.b=t1.a"); "right outer join t3 on t1.b=t3.a right outer join t2 on t2.b=t1.a");
...@@ -571,7 +571,7 @@ public class TestOuterJoins extends TestBase { ...@@ -571,7 +571,7 @@ public class TestOuterJoins extends TestBase {
// } // }
conn.close(); conn.close();
deleteDb("nestedJoins"); deleteDb("outerJoins");
} }
private static String cleanRemarks(String sql) { private static String cleanRemarks(String sql) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论