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

Huge headway in testing

上级 bb5c0974
......@@ -21,7 +21,7 @@ OFFSET specified how many rows to skip.
Please note using high offset values should be avoided because it can cause performance problems.
SAMPLE_SIZE limits the number of rows read for aggregate queries.
Multiple set operators (UNION, INTERSECT, MINUS, EXPECT) are evaluated
Multiple set operators (UNION, INTERSECT, MINUS, EXCEPT) are evaluated
from left to right. For compatibility with other databases and future versions
of H2 please use parentheses.
......
......@@ -1138,10 +1138,9 @@ public class Parser {
String[] querySQLOutput = new String[]{null};
List<Column> columnTemplateList = createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput);
System.out.println("pre:alias="+command.getQueryAlias()+",sql="+querySQLOutput[0]+",ctlist="+columnTemplateList+",schema="+getSchema()+",schemaName="+schemaName);
TableView temporarySourceTableView = createTemporarySessionView(command.getQueryAlias(), querySQLOutput[0], columnTemplateList, false);
TableView temporarySourceTableView = createTemporarySessionView(command.getQueryAlias(), querySQLOutput[0], columnTemplateList, false, false);
command.setTemporaryTableView(temporarySourceTableView);
//Table tableOrView = command.getQuery().getTables().toArray(new Table[]{null})[0];
System.out.println("sourceTableFilter with tableOrView="+temporarySourceTableView);
System.out.println("sourceTableFilter rightsChecked="+rightsChecked);
TableFilter sourceTableFilter = new TableFilter(session, temporarySourceTableView, command.getQueryAlias(), rightsChecked,
......@@ -5190,7 +5189,7 @@ public class Parser {
} finally {
session.removeLocalTempTable(recursiveTable);
}
TableView view = createTemporarySessionView(tempViewName, querySQLOutput[0], columnTemplateList,true/*allowRecursiveQueryDetection*/);
TableView view = createTemporarySessionView(tempViewName, querySQLOutput[0], columnTemplateList,true/*allowRecursiveQueryDetection*/, true);
return view;
}
......@@ -5201,18 +5200,26 @@ public class Parser {
ArrayList<Expression> withExpressions = withQuery.getExpressions();
System.out.println("withExpressions="+withExpressions);
for (int i = 0; i < withExpressions.size(); ++i) {
Expression withExp = withExpressions.get(i);
System.out.println("withExp.alias="+withExp.getAlias()+",name="+withExp.getColumnName());
String columnName = cols != null ? cols[i]
: (withExp.getAlias()!=null ? withExp.getAlias() : withExp.getColumnName());
Expression columnExp = withExpressions.get(i);
// use the passed in column name if supplied, otherwise use alias (if used) otherwise use column name
// derived from column expression
String columnName;
if (cols != null){
columnName = cols[i];
} else if (columnExp.getAlias()!=null){
columnName = columnExp.getAlias();
}
else{
columnName = columnExp.getColumnName();
}
columnTemplateList.add(new Column(columnName,
withExpressions.get(i).getType()));
columnExp.getType()));
}
return columnTemplateList;
}
private TableView createTemporarySessionView(String tempViewName, String querySQL,
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection) {
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection, boolean addViewToSession) {
Schema schema = getSchema();
int id = database.allocateObjectId();
// No easy way to determine if this is a recursive query up front, so we just compile
......@@ -5229,7 +5236,9 @@ public class Parser {
}
view.setTableExpression(true);
view.setTemporary(true);
if(addViewToSession){
session.addLocalTempTable(view);
}
view.setOnCommitDrop(true);
return view;
}
......
......@@ -361,7 +361,7 @@ public class Session extends SessionWithState {
}
if (localTempTables.get(table.getName()) != null) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
table.getSQL());
table.getSQL()+" AS "+table.getName());
}
modificationId++;
localTempTables.put(table.getName(), table);
......
......@@ -9,7 +9,6 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import org.h2.test.TestBase;
/**
* Test merge using syntax.
......@@ -17,6 +16,8 @@ import org.h2.test.TestBase;
public class TestMergeUsing extends TestBase {
private static final String GATHER_ORDERED_RESULTS_SQL = "SELECT ID, NAME FROM PARENT ORDER BY ID ASC";
/**
* Run just this test.
*
......@@ -28,35 +29,86 @@ public class TestMergeUsing extends TestBase {
@Override
public void test() throws Exception {
testMergeUsing();
// Simple ID,NAME inserts, target table with PK initially empty
testMergeUsing(
"CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)",
2
);
// Simple NAME updates, target table missing PK
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE 1 = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)",
2
);
// No NAME updates, WHERE clause is always false, insert clause missing
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE 1 = 2",
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)",
0
);
// No NAME updates, no WHERE clause, insert clause missing
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID",
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)",
2
);
// Two delete updates done, no WHERE clause, insert clause missing
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN DELETE",
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) WHERE 1=0",
2
);
// One insert, one update one delete happens, target table missing PK
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3
);
}
private void testMergeUsing() throws Exception {
private void testMergeUsing(String setupSQL, String statementUnderTest, String gatherResultsSQL,
String expectedResultsSQL, int expectedRowUpdateCount) throws Exception {
deleteDb("mergeUsingQueries");
Connection conn = getConnection("mergeUsingQueries");
Statement stat;
PreparedStatement prep;
ResultSet rs;
int rowCount;
int rowCountUpdate;
stat = conn.createStatement();
stat.execute("CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );");
stat.execute(setupSQL);
prep = conn.prepareStatement("MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)");
rowCount = prep.executeUpdate();
prep = conn.prepareStatement(statementUnderTest);
rowCountUpdate = prep.executeUpdate();
int[] rowArray = new int[] { 1,2 };
assertEquals(rowArray.length,rowCount);
rs = stat.executeQuery("( "+gatherResultsSQL+" ) MINUS ( "+expectedResultsSQL+" )");
rs = stat.executeQuery("SELECT ID, NAME FROM PARENT ORDER BY ID ASC");
for (int n : rowArray) {
assertTrue(rs.next());
assertEquals(n,rs.getInt(1));
assertEquals("Marcy"+n, rs.getString(2));
System.out.println("id="+rs.getInt(1)+",name="+rs.getString(2));
int rowCount = 0;
StringBuffer diffBuffer = new StringBuffer("");
while (rs.next()) {
rowCount++;
diffBuffer.append("|");
for(int ndx = 0; ndx < rs.getMetaData().getColumnCount(); ndx++){
diffBuffer.append(rs.getObject(ndx));
diffBuffer.append("|\n");
}
}
assertFalse(rs.next());
assertEquals("Differences is expected output found:"+diffBuffer,0,rowCount);
assertEquals("Expected update counts differ",expectedRowUpdateCount,rowCountUpdate);
conn.close();
deleteDb("mergeUsingQueries");
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论