提交 17d2a88c authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #302 from igelbox/recursive-with-join-and-subqueries

add support for "with"-subqueries into "join" & "sub-query" statements
...@@ -477,8 +477,8 @@ public class Parser { ...@@ -477,8 +477,8 @@ public class Parser {
break; break;
case 'w': case 'w':
case 'W': case 'W':
if (readIf("WITH")) { if (isToken("WITH")) {
c = parseWith(); c = parseSelect();
} }
break; break;
case ';': case ';':
...@@ -999,7 +999,7 @@ public class Parser { ...@@ -999,7 +999,7 @@ public class Parser {
// need to read ahead, it could be a nested union: // need to read ahead, it could be a nested union:
// ((select 1) union (select 1)) // ((select 1) union (select 1))
} }
boolean select = isToken("SELECT") || isToken("FROM"); boolean select = isToken("SELECT") || isToken("FROM") || isToken("WITH");
parseIndex = start; parseIndex = start;
read(); read();
return select; return select;
...@@ -1676,7 +1676,7 @@ public class Parser { ...@@ -1676,7 +1676,7 @@ public class Parser {
readIf("FOR"); readIf("FOR");
} }
} }
if (isToken("SELECT") || isToken("FROM") || isToken("(")) { if (isToken("SELECT") || isToken("FROM") || isToken("(") || isToken("WITH")) {
command.setCommand(parseSelect()); command.setCommand(parseSelect());
} else if (readIf("DELETE")) { } else if (readIf("DELETE")) {
command.setCommand(parseDelete()); command.setCommand(parseDelete());
...@@ -1686,8 +1686,6 @@ public class Parser { ...@@ -1686,8 +1686,6 @@ public class Parser {
command.setCommand(parseInsert()); command.setCommand(parseInsert());
} else if (readIf("MERGE")) { } else if (readIf("MERGE")) {
command.setCommand(parseMerge()); command.setCommand(parseMerge());
} else if (readIf("WITH")) {
command.setCommand(parseWith());
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
} }
...@@ -1887,6 +1885,8 @@ public class Parser { ...@@ -1887,6 +1885,8 @@ public class Parser {
read(")"); read(")");
return command; return command;
} }
if (readIf("WITH"))
return parseWith();
Select select = parseSelectSimple(); Select select = parseSelectSimple();
return select; return select;
} }
...@@ -2772,12 +2772,9 @@ public class Parser { ...@@ -2772,12 +2772,9 @@ public class Parser {
r = p; r = p;
break; break;
case KEYWORD: case KEYWORD:
if (isToken("SELECT") || isToken("FROM")) { if (isToken("SELECT") || isToken("FROM") || isToken("WITH")) {
Query query = parseSelect(); Query query = parseSelect();
r = new Subquery(query); r = new Subquery(query);
} else if (readIf("WITH")) {
Query query = parseWith();
r = new Subquery(query);
} else { } else {
throw getSyntaxError(); throw getSyntaxError();
} }
...@@ -4781,7 +4778,7 @@ public class Parser { ...@@ -4781,7 +4778,7 @@ public class Parser {
view.setTemporary(true); view.setTemporary(true);
session.addLocalTempTable(view); session.addLocalTempTable(view);
view.setOnCommitDrop(true); view.setOnCommitDrop(true);
Query q = parseSelect(); Query q = parseSelectUnion();
q.setPrepareAlways(true); q.setPrepareAlways(true);
return q; return q;
} }
......
...@@ -38,6 +38,7 @@ import org.h2.table.IndexColumn; ...@@ -38,6 +38,7 @@ import org.h2.table.IndexColumn;
import org.h2.table.JoinBatch; import org.h2.table.JoinBatch;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.table.TableView;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -1082,7 +1083,21 @@ public class Select extends Query { ...@@ -1082,7 +1083,21 @@ public class Select extends Query {
// but indexes may be set manually as well // but indexes may be set manually as well
Expression[] exprList = expressions.toArray( Expression[] exprList = expressions.toArray(
new Expression[expressions.size()]); new Expression[expressions.size()]);
StatementBuilder buff = new StatementBuilder("SELECT"); StatementBuilder buff = new StatementBuilder();
for (TableFilter f : topFilters) {
Table t = f.getTable();
if ((t instanceof TableView) && ((TableView) t).isRecursive()) {
buff.append("WITH RECURSIVE ").append(t.getName()).append('(');
buff.resetCount();
for (Column c : t.getColumns()) {
buff.appendExceptFirst(",");
buff.append(c.getName());
}
buff.append(") AS ").append(t.getSQL()).append("\n");
}
}
buff.resetCount();
buff.append("SELECT");
if (distinct) { if (distinct) {
buff.append(" DISTINCT"); buff.append(" DISTINCT");
} }
......
...@@ -816,7 +816,10 @@ public class TableFilter implements ColumnResolver { ...@@ -816,7 +816,10 @@ public class TableFilter implements ColumnResolver {
} }
return buff.toString(); return buff.toString();
} }
buff.append(table.getSQL()); if ((table instanceof TableView) && ((TableView) table).isRecursive())
buff.append(table.getName());
else
buff.append(table.getSQL());
if (table.isView() && ((TableView) table).isInvalid()) { if (table.isView() && ((TableView) table).isInvalid()) {
throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, table.getName(), "not compiled"); throw DbException.get(ErrorCode.VIEW_IS_INVALID_2, table.getName(), "not compiled");
} }
......
...@@ -579,6 +579,10 @@ public class TableView extends Table { ...@@ -579,6 +579,10 @@ public class TableView extends Table {
return result; return result;
} }
public boolean isRecursive() {
return recursive;
}
@Override @Override
public boolean isDeterministic() { public boolean isDeterministic() {
if (recursive || viewQuery == null) { if (recursive || viewQuery == null) {
......
...@@ -10228,6 +10228,49 @@ select 0 from (( ...@@ -10228,6 +10228,49 @@ select 0 from ((
}; };
> update count: 0 > update count: 0
explain with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r;
> PLAN
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> WITH RECURSIVE R(N) AS ( (SELECT 1 FROM SYSTEM_RANGE(1, 1) /* PUBLIC.RANGE_INDEX */) UNION ALL (SELECT (N + 1) FROM PUBLIC.R /* PUBLIC.R.tableScan */ WHERE N < 3) ) SELECT N FROM R /* null */
> rows: 1
select sum(n) from (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
);
> SUM(N)
> ------
> 6
> rows: 1
select sum(n) from (select 0) join (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
) on 1=1;
> SUM(N)
> ------
> 6
> rows: 1
select 0 from (
select 0 where 0 in (
with recursive r(n) as (
(select 1) union all (select n+1 from r where n < 3)
)
select n from r
)
);
> 0
> -
> rows: 0
create table x(id int not null); create table x(id int not null);
> ok > ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论