提交 9c0dfc7a authored 作者: Owner's avatar Owner

Issue#479

上级 8582753e
......@@ -17,6 +17,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import org.h2.api.ErrorCode;
import org.h2.api.Trigger;
import org.h2.command.ddl.AlterIndexRename;
......@@ -74,6 +75,7 @@ import org.h2.command.dml.Insert;
import org.h2.command.dml.Merge;
import org.h2.command.dml.NoOperation;
import org.h2.command.dml.Query;
import org.h2.command.dml.RecursiveQuery;
import org.h2.command.dml.Replace;
import org.h2.command.dml.RunScriptCommand;
import org.h2.command.dml.ScriptCommand;
......@@ -4852,7 +4854,7 @@ public class Parser {
return command;
}
private Query parseWith() {
private Query parseWithOriginal() {
readIf("RECURSIVE");
String tempViewName = readIdentifierWithSchema();
Schema schema = getSchema();
......@@ -4915,6 +4917,74 @@ public class Parser {
return q;
}
// SBM THis is where we work !
private Query parseWith() {
readIf("RECURSIVE");
do{
String tempViewName = readIdentifierWithSchema();
Schema schema = getSchema();
Table recursiveTable;
read("(");
ArrayList<Column> columns = New.arrayList();
String[] cols = parseColumnList();
for (String c : cols) {
columns.add(new Column(c, Value.STRING));
}
Table old = session.findLocalTempTable(tempViewName);
if (old != null) {
if (!(old instanceof TableView)) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
tempViewName);
}
TableView tv = (TableView) old;
if (!tv.isTableExpression()) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
tempViewName);
}
session.removeLocalTempTable(old);
}
CreateTableData data = new CreateTableData();
data.id = database.allocateObjectId();
data.columns = columns;
data.tableName = tempViewName;
data.temporary = true;
data.persistData = true;
data.persistIndexes = false;
data.create = true;
data.session = session;
recursiveTable = schema.createTable(data);
session.addLocalTempTable(recursiveTable);
String querySQL;
Column[] columnTemplates = new Column[cols.length];
try {
read("AS");
read("(");
Query withQuery = parseSelect();
read(")");
withQuery.prepare();
querySQL = StringUtils.cache(withQuery.getPlanSQL());
ArrayList<Expression> withExpressions = withQuery.getExpressions();
for (int i = 0; i < cols.length; ++i) {
columnTemplates[i] = new Column(cols[i], withExpressions.get(i).getType());
}
} finally {
session.removeLocalTempTable(recursiveTable);
}
int id = database.allocateObjectId();
TableView view = new TableView(schema, id, tempViewName, querySQL,
parameters, columnTemplates, session, RecursiveQuery.isRecursive(tempViewName,querySQL));
view.setTableExpression(true);
view.setTemporary(true);
session.addLocalTempTable(view);
view.setOnCommitDrop(true);
} while(readIf(","));
Query q = parseSelectUnion();
q.setPrepareAlways(true);
return q;
}
private CreateView parseCreateView(boolean force, boolean orReplace) {
boolean ifNotExists = readIfNotExists();
String viewName = readIdentifierWithSchema();
......
package org.h2.command.dml;
import java.util.regex.Pattern;
public class RecursiveQuery {
// A query is recursive if it references it's own name in its definition
public static boolean isRecursive(String tempViewName, String querySQL) {
return Pattern.matches("\\b"+tempViewName+"\\b",querySQL);
}
}
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.test.db;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import org.h2.test.TestBase;
/**
* Test non-recursive queries using WITH, but more than one common table defined.
*/
public class TestGeneralCommonTableQueries extends TestBase {
private static final String SIMPLE_TWO_COMMON_QUERY = "with " +
"t1(n) as (select 1 as first) " +
",t2(n) as (select 2 as first) " +
"select * from t1 union all select * from t2";
private static final String PARAMETERIZED_TWO_COMMON_QUERY = "with " +
"t1(n) as (select 2 as first) " +
",t2(n) as (select 3 as first) " +
"select * from t1 union all select * from t2 where n<>?";
private static final String PARAMETERIZED_THREE_COMMON_QUERY = "with " +
"t1(n) as (select 2 as first) " +
",t2(n) as (select 3 as first) " +
",t3(n) as (select 4 as first) " +
"select * from t1 union all select * from t2 union all select * from t3 where n<>?";
/**
* Run just this test.
*
* @param a ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
System.out.println("Testing done");
}
@Override
public void test() throws Exception {
testSimple();
}
private void testSimple() throws Exception {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
Statement stat;
PreparedStatement prep;
ResultSet rs;
stat = conn.createStatement();
rs = stat.executeQuery(SIMPLE_TWO_COMMON_QUERY);
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(SIMPLE_TWO_COMMON_QUERY);
rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(PARAMETERIZED_TWO_COMMON_QUERY);
prep.setInt(1, 0); // omit no lines since zero is not in list
rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertFalse(rs.next());
prep = conn.prepareStatement(PARAMETERIZED_THREE_COMMON_QUERY);
prep.setInt(1, 4); // omit 4 line (last)
rs = prep.executeQuery();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertFalse(rs.next());
conn.close();
deleteDb("commonTableExpressionQueries");
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论