提交 bf03bc6d authored 作者: Owner's avatar Owner

Found & fixed bug in column types from persisted store.

上级 b2e546f3
......@@ -1051,7 +1051,7 @@ public class Parser {
}
}
private static Prepared prepare(Session s, String sql,
public static Prepared prepare(Session s, String sql,
ArrayList<Value> paramValues) {
Prepared prep = s.prepare(sql);
ArrayList<Parameter> params = prep.getParameters();
......@@ -5169,6 +5169,7 @@ public class Parser {
// as in CREATE VIEW abc AS WITH my_cte - this auto detects that condition
if(session.isParsingView()){
isPersistent = true;
System.out.println("getParsingViewName="+session.getParsingViewName());
}
do {
......@@ -5360,7 +5361,7 @@ public class Parser {
* Query object
* @return a list of column object returned by withQuery
*/
private static List<Column> createQueryColumnTemplateList(String[] cols,
public static List<Column> createQueryColumnTemplateList(String[] cols,
Query theQuery, String[] querySQLOutput) {
List<Column> columnTemplateList = new ArrayList<>();
theQuery.prepare();
......
......@@ -79,7 +79,8 @@ import org.h2.value.Value;
* 4) Previously if neither UPDATE or DELETE clause is supplied, but INSERT is supplied - the INSERT
* action is always triggered. This is because the embedded UPDATE and DELETE statement's
* returned update row count is used to detect a matching join.
* If neither of the two the statements are provided, no matching join is EVER detected.
* If neither of the two the statements are provided, no matching join is NEVER detected.
*
* A fix for this is now implemented as described below:
* We now generate a "matchSelect" query and use that to always detect
* a match join - rather than relying on UPDATE or DELETE statements.
......
......@@ -765,7 +765,7 @@ public class Database implements DataHandler {
Collections.sort(records);
synchronized (systemSession) {
for (MetaRecord rec : records) {
rec.execute(this, systemSession, eventListener);
rec.execute(this, systemSession, eventListener);
}
}
if (mvStore != null) {
......
......@@ -11,6 +11,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.h2.api.ErrorCode;
import org.h2.command.Parser;
import org.h2.command.Prepared;
import org.h2.command.dml.Query;
import org.h2.engine.Constants;
......@@ -713,9 +714,32 @@ public class TableView extends Table {
ArrayList<Parameter> parameters, Column[] columnTemplates, Session session,
boolean literalsChecked, boolean isTableExpression, boolean isPersistent, Database db){
Table recursiveTable = Parser.createShadowTableForRecursiveTableExpression(isPersistent, session, name,
schema, Arrays.asList(columnTemplates), db);
List<Column> columnTemplateList;
String[] querySQLOutput = new String[]{null};
ArrayList<String> columnNames = new ArrayList<String>();
for(Column columnTemplate: columnTemplates){
columnNames.add(columnTemplate.getName());
}
try {
Prepared withQuery = session.prepare(querySQL, false, false);
if(isPersistent){
withQuery.setSession(session);
}
columnTemplateList = Parser.createQueryColumnTemplateList(columnNames.toArray(new String[1]),
(Query) withQuery, querySQLOutput);
} finally {
Parser.destroyShadowTableForRecursiveExpression(isPersistent, session, recursiveTable);
}
// build with recursion turned on
TableView view = new TableView(schema, id, name, querySQL,
parameters, columnTemplates, session,
parameters, columnTemplateList.toArray(columnTemplates), session,
true/* try recursive */, literalsChecked, isTableExpression, isPersistent );
// is recursion really detected ? if not - recreate it without recursion flag and no recursive index
......
......@@ -10,7 +10,7 @@ import org.h2.test.TestBase;
public abstract class AbstractBaseForCommonTableExpressions extends TestBase {
protected void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames, int expectedNumbeOfRows, String SETUP_SQL,
String WITH_QUERY, int closeAndReopenDatabaseConnectionOnIteration) throws SQLException {
String WITH_QUERY, int closeAndReopenDatabaseConnectionOnIteration, String[] expectedColumnTypes) throws SQLException {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
......@@ -37,6 +37,8 @@ public abstract class AbstractBaseForCommonTableExpressions extends TestBase {
assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null);
assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex));
assertEquals("wrongly type column "+rs.getMetaData().getColumnLabel(columnIndex)+" on iteration#"+queryRunTries,
expectedColumnTypes[columnIndex-1],rs.getMetaData().getColumnTypeName(columnIndex));
}
int rowNdx=0;
......
......@@ -41,7 +41,7 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
testMerge();
testCreateTable();
testNestedSQL();
testRecursiveTable();
testLazyQueryExecutionAndRecursiveTable();
}
private void testSimpleSelect() throws Exception {
......@@ -469,66 +469,27 @@ public class TestGeneralCommonTableQueries extends AbstractBaseForCommonTableExp
conn.close();
deleteDb("commonTableExpressionQueries");
}
private void testRecursiveTable() throws Exception {
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n" +
" X\n" +
"FROM PUBLIC.\"\" BB\n" +
" /* SELECT\n" +
" SUM(1) AS X,\n" +
" A\n" +
" FROM PUBLIC.B\n" +
" /++ PUBLIC.B.tableScan ++/\n" +
" /++ WHERE A IS ?1\n" +
" ++/\n" +
" /++ scanCount: 4 ++/\n" +
" INNER JOIN PUBLIC.C\n" +
" /++ PUBLIC.C.tableScan ++/\n" +
" ON 1=1\n" +
" WHERE (A IS ?1)\n" +
" AND (B.VAL = C.B)\n" +
" GROUP BY A: A IS A.VAL\n" +
" */\n" +
" /* scanCount: 1 */\n" +
"WHERE BB.A IS A.VAL)"};
String SETUP_SQL =
"DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; "
+"CREATE TABLE A(VAL VARCHAR(255)); "
+"CREATE TABLE B(A VARCHAR(255), VAL VARCHAR(255)); "
+"CREATE TABLE C(B VARCHAR(255), VAL VARCHAR(255)); "
+" "
+"INSERT INTO A VALUES('fruit'); "
+"INSERT INTO B VALUES('fruit','apple'); "
+"INSERT INTO B VALUES('fruit','banana'); "
+"INSERT INTO C VALUES('apple', 'golden delicious');"
+"INSERT INTO C VALUES('apple', 'granny smith'); "
+"INSERT INTO C VALUES('apple', 'pippin'); "
+"INSERT INTO A VALUES('veg'); "
+"INSERT INTO B VALUES('veg', 'carrot'); "
+"INSERT INTO C VALUES('carrot', 'nantes'); "
+"INSERT INTO C VALUES('carrot', 'imperator'); "
+"INSERT INTO C VALUES(null, 'banapple'); "
+"INSERT INTO A VALUES('meat'); "
private void testLazyQueryExecutionAndRecursiveTable() throws Exception {
String[] expectedRowData =new String[]{"|1","|2","|3"};
String[] expectedColumnTypes =new String[]{"INTEGER"};
String[] expectedColumnNames =new String[]{"N"};
//Test lazy mvStore memory mvcc multiThreaded
String SETUP_SQL = "SET LAZY_QUERY_EXECUTION 1;\n"
//+ "SET MEMORY 1;SET MV_STORE true; SET MVCC TRUE;"
//+ "SET MULTI_THREADED TRUE;"
;
String WITH_QUERY = "WITH BB as (SELECT \n" +
"sum(1) as X, \n" +
"a \n" +
"FROM B \n" +
"JOIN C ON B.val=C.b \n" +
"GROUP BY a) \n" +
"SELECT \n" +
"A.val, \n" +
"sum(SELECT X FROM BB WHERE BB.a IS A.val)\n" +
"FROM A \n" + "GROUP BY A.val";
String WITH_QUERY = "with recursive r(n) as (\n"+
"(select 1) union all (select n+1 from r where n < 3)\n"+
")\n"+
"select n from r";
int maxRetries = 3;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
WITH_QUERY, maxRetries-1, expectedColumnTypes);
}
}
}
......@@ -30,53 +30,69 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
}
private void testRecursiveTable() throws Exception {
int maxRetries = 4;
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnTypes =new String[]{"VARCHAR","DECIMAL"};
String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n X\nFROM PUBLIC.\"\" BB\n /* SELECT\n SUM(1) AS X,\n A\n FROM PUBLIC.B\n /++ PUBLIC.B.tableScan ++/\n /++ WHERE A IS ?1\n ++/\n /++ scanCount: 4 ++/\n INNER JOIN PUBLIC.C\n /++ PUBLIC.C.tableScan ++/\n ON 1=1\n WHERE (A IS ?1)\n AND (B.VAL = C.B)\n GROUP BY A: A IS A.VAL\n */\n /* scanCount: 1 */\nWHERE BB.A IS A.VAL)"};
int expectedNumberOfRows = 3;
"SUM(SELECT\n" +
" X\n" +
"FROM PUBLIC.\"\" BB\n" +
" /* SELECT\n" +
" SUM(1) AS X,\n" +
" A\n" +
" FROM PUBLIC.B\n" +
" /++ PUBLIC.B.tableScan ++/\n" +
" /++ WHERE A IS ?1\n" +
" ++/\n" +
" /++ scanCount: 4 ++/\n" +
" INNER JOIN PUBLIC.C\n" +
" /++ PUBLIC.C.tableScan ++/\n" +
" ON 1=1\n" +
" WHERE (A IS ?1)\n" +
" AND (B.VAL = C.B)\n" +
" GROUP BY A: A IS A.VAL\n" +
" */\n" +
" /* scanCount: 1 */\n" +
"WHERE BB.A IS A.VAL)"};
String SETUP_SQL =
String SETUP_SQL =
"DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; "
+"CREATE TABLE A(VAL VARCHAR(255)); "
+"CREATE TABLE B(A VARCHAR(255), VAL VARCHAR(255)); "
+"CREATE TABLE C(B VARCHAR(255), VAL VARCHAR(255)); "
+" "
+"INSERT INTO A VALUES('fruit'); "
+"INSERT INTO B VALUES('fruit','apple'); "
+"INSERT INTO B VALUES('fruit','banana'); "
+"INSERT INTO C VALUES('apple', 'golden delicious');"
+"INSERT INTO C VALUES('apple', 'granny smith'); "
+"INSERT INTO C VALUES('apple', 'pippin'); "
+"INSERT INTO A VALUES('veg'); "
+"INSERT INTO B VALUES('veg', 'carrot'); "
+"INSERT INTO C VALUES('carrot', 'nantes'); "
+"INSERT INTO C VALUES('carrot', 'imperator'); "
+"INSERT INTO C VALUES(null, 'banapple'); "
+"INSERT INTO A VALUES('meat'); "
;
String WITH_QUERY =
"WITH BB as (SELECT \n"
+"sum(1) as X, \n"
+"a \n"
+"FROM B \n"
+"JOIN C ON B.val=C.b \n"
+"GROUP BY a) \n"
+"SELECT \n"
+"A.val, \n"
+"sum(SELECT X FROM BB WHERE BB.a IS A.val)\n"
+"FROM A \n"
+"GROUP BY A.val";
+"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; "
+"CREATE TABLE A(VAL VARCHAR(255)); "
+"CREATE TABLE B(A VARCHAR(255), VAL VARCHAR(255)); "
+"CREATE TABLE C(B VARCHAR(255), VAL VARCHAR(255)); "
+" "
+"INSERT INTO A VALUES('fruit'); "
+"INSERT INTO B VALUES('fruit','apple'); "
+"INSERT INTO B VALUES('fruit','banana'); "
+"INSERT INTO C VALUES('apple', 'golden delicious');"
+"INSERT INTO C VALUES('apple', 'granny smith'); "
+"INSERT INTO C VALUES('apple', 'pippin'); "
+"INSERT INTO A VALUES('veg'); "
+"INSERT INTO B VALUES('veg', 'carrot'); "
+"INSERT INTO C VALUES('carrot', 'nantes'); "
+"INSERT INTO C VALUES('carrot', 'imperator'); "
+"INSERT INTO C VALUES(null, 'banapple'); "
+"INSERT INTO A VALUES('meat'); "
;
String WITH_QUERY = "WITH BB as (SELECT \n" +
"sum(1) as X, \n" +
"a \n" +
"FROM B \n" +
"JOIN C ON B.val=C.b \n" +
"GROUP BY a) \n" +
"SELECT \n" +
"A.val, \n" +
"sum(SELECT X FROM BB WHERE BB.a IS A.val)\n" +
"FROM A \n" + "GROUP BY A.val";
int maxRetries = 3;
int expectedNumberOfRows = expectedRowData.length;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
WITH_QUERY, maxRetries-1, expectedColumnTypes);
}
private void testPersistentRecursiveTableInCreateView() throws Exception {
String SETUP_SQL = "--SET TRACE_LEVEL_SYSTEM_OUT 3;\n"
+"DROP TABLE IF EXISTS my_tree; \n"
......@@ -120,10 +136,12 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
"|1|2|null|121"
};
String[] expectedColumnNames =new String[]{"SUB_TREE_ROOT_ID","TREE_LEVEL","PARENT_FK","CHILD_FK"};
String[] expectedColumnTypes =new String[]{"INTEGER","INTEGER","INTEGER","INTEGER"};
int expectedNumberOfRows = 11;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
WITH_QUERY, maxRetries-1,expectedColumnTypes);
}
private void testPersistentNonRecursiveTableInCreateView() throws Exception {
String SETUP_SQL = ""
+"DROP VIEW IF EXISTS v_my_nr_tree; \n"
......@@ -158,8 +176,9 @@ public class TestPersistentCommonTableExpressions extends AbstractBaseForCommonT
"|121|0|12|121",
};
String[] expectedColumnNames =new String[]{"SUB_TREE_ROOT_ID","TREE_LEVEL","PARENT_FK","CHILD_FK"};
String[] expectedColumnTypes =new String[]{"INTEGER","INTEGER","INTEGER","INTEGER"};
int expectedNumberOfRows = 5;
testRepeatedQueryWithSetup(maxRetries, expectedRowData, expectedColumnNames, expectedNumberOfRows, SETUP_SQL,
WITH_QUERY, maxRetries-1);
WITH_QUERY, maxRetries-1, expectedColumnTypes);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论