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

Huge headway in testing

上级 bb5c0974
...@@ -21,7 +21,7 @@ OFFSET specified how many rows to skip. ...@@ -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. 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. 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 from left to right. For compatibility with other databases and future versions
of H2 please use parentheses. of H2 please use parentheses.
......
...@@ -1138,10 +1138,9 @@ public class Parser { ...@@ -1138,10 +1138,9 @@ public class Parser {
String[] querySQLOutput = new String[]{null}; String[] querySQLOutput = new String[]{null};
List<Column> columnTemplateList = createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput); List<Column> columnTemplateList = createQueryColumnTemplateList(null, command.getQuery(), querySQLOutput);
System.out.println("pre:alias="+command.getQueryAlias()+",sql="+querySQLOutput[0]+",ctlist="+columnTemplateList+",schema="+getSchema()+",schemaName="+schemaName); 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); command.setTemporaryTableView(temporarySourceTableView);
//Table tableOrView = command.getQuery().getTables().toArray(new Table[]{null})[0];
System.out.println("sourceTableFilter with tableOrView="+temporarySourceTableView); System.out.println("sourceTableFilter with tableOrView="+temporarySourceTableView);
System.out.println("sourceTableFilter rightsChecked="+rightsChecked); System.out.println("sourceTableFilter rightsChecked="+rightsChecked);
TableFilter sourceTableFilter = new TableFilter(session, temporarySourceTableView, command.getQueryAlias(), rightsChecked, TableFilter sourceTableFilter = new TableFilter(session, temporarySourceTableView, command.getQueryAlias(), rightsChecked,
...@@ -5190,7 +5189,7 @@ public class Parser { ...@@ -5190,7 +5189,7 @@ public class Parser {
} finally { } finally {
session.removeLocalTempTable(recursiveTable); session.removeLocalTempTable(recursiveTable);
} }
TableView view = createTemporarySessionView(tempViewName, querySQLOutput[0], columnTemplateList,true/*allowRecursiveQueryDetection*/); TableView view = createTemporarySessionView(tempViewName, querySQLOutput[0], columnTemplateList,true/*allowRecursiveQueryDetection*/, true);
return view; return view;
} }
...@@ -5201,18 +5200,26 @@ public class Parser { ...@@ -5201,18 +5200,26 @@ public class Parser {
ArrayList<Expression> withExpressions = withQuery.getExpressions(); ArrayList<Expression> withExpressions = withQuery.getExpressions();
System.out.println("withExpressions="+withExpressions); System.out.println("withExpressions="+withExpressions);
for (int i = 0; i < withExpressions.size(); ++i) { for (int i = 0; i < withExpressions.size(); ++i) {
Expression withExp = withExpressions.get(i); Expression columnExp = withExpressions.get(i);
System.out.println("withExp.alias="+withExp.getAlias()+",name="+withExp.getColumnName()); // use the passed in column name if supplied, otherwise use alias (if used) otherwise use column name
String columnName = cols != null ? cols[i] // derived from column expression
: (withExp.getAlias()!=null ? withExp.getAlias() : withExp.getColumnName()); 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, columnTemplateList.add(new Column(columnName,
withExpressions.get(i).getType())); columnExp.getType()));
} }
return columnTemplateList; return columnTemplateList;
} }
private TableView createTemporarySessionView(String tempViewName, String querySQL, private TableView createTemporarySessionView(String tempViewName, String querySQL,
List<Column> columnTemplateList, boolean allowRecursiveQueryDetection) { List<Column> columnTemplateList, boolean allowRecursiveQueryDetection, boolean addViewToSession) {
Schema schema = getSchema(); Schema schema = getSchema();
int id = database.allocateObjectId(); int id = database.allocateObjectId();
// No easy way to determine if this is a recursive query up front, so we just compile // No easy way to determine if this is a recursive query up front, so we just compile
...@@ -5229,7 +5236,9 @@ public class Parser { ...@@ -5229,7 +5236,9 @@ public class Parser {
} }
view.setTableExpression(true); view.setTableExpression(true);
view.setTemporary(true); view.setTemporary(true);
session.addLocalTempTable(view); if(addViewToSession){
session.addLocalTempTable(view);
}
view.setOnCommitDrop(true); view.setOnCommitDrop(true);
return view; return view;
} }
......
...@@ -7,6 +7,7 @@ package org.h2.command.dml; ...@@ -7,6 +7,7 @@ package org.h2.command.dml;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.Prepared; import org.h2.command.Prepared;
...@@ -42,6 +43,7 @@ public class MergeUsing extends Merge { ...@@ -42,6 +43,7 @@ public class MergeUsing extends Merge {
private Insert insertCommand; private Insert insertCommand;
private String queryAlias; private String queryAlias;
private TableView temporarySourceTableView; private TableView temporarySourceTableView;
private int countUpdatedRows=0;
public MergeUsing(Merge merge) { public MergeUsing(Merge merge) {
super(merge.getSession()); super(merge.getSession());
...@@ -67,22 +69,22 @@ public class MergeUsing extends Merge { ...@@ -67,22 +69,22 @@ public class MergeUsing extends Merge {
sourceTableFilter.reset(); sourceTableFilter.reset();
} }
int count; int countInputRows;
checkRights(); checkRights();
setCurrentRowNumber(0); setCurrentRowNumber(0);
// process select query data for row creation // process select query data for row creation
ResultInterface rows = query.query(0); ResultInterface rows = query.query(0);
count = 0; countInputRows = 0;
targetTable.fire(session, evaluateTriggerMasks(), true); targetTable.fire(session, evaluateTriggerMasks(), true);
targetTable.lock(session, true, false); targetTable.lock(session, true, false);
while (rows.next()) { while (rows.next()) {
count++; countInputRows++;
Value[] sourceRowValues = rows.currentRow(); Value[] sourceRowValues = rows.currentRow();
Row sourceRow = new RowImpl(sourceRowValues,0); Row sourceRow = new RowImpl(sourceRowValues,0);
System.out.println(("currentRowValues="+Arrays.toString(sourceRowValues))); System.out.println(("currentRowValues="+Arrays.toString(sourceRowValues)));
Row newTargetRow = targetTable.getTemplateRow(); Row newTargetRow = targetTable.getTemplateRow();
setCurrentRowNumber(count); setCurrentRowNumber(countInputRows);
System.out.println("columns="+Arrays.toString(columns)); System.out.println("columns="+Arrays.toString(columns));
// computer the new target row columns values // computer the new target row columns values
...@@ -93,14 +95,14 @@ public class MergeUsing extends Merge { ...@@ -93,14 +95,14 @@ public class MergeUsing extends Merge {
Value v = c.convert(sourceRowValues[j]); Value v = c.convert(sourceRowValues[j]);
newTargetRow.setValue(index, v); newTargetRow.setValue(index, v);
} catch (DbException ex) { } catch (DbException ex) {
throw setRow(ex, count, getSQL(sourceRowValues)); throw setRow(ex, countInputRows, getSQL(sourceRowValues));
} }
} }
merge(sourceRow, sourceRowValues,newTargetRow); merge(sourceRow, sourceRowValues,newTargetRow);
} }
rows.close(); rows.close();
targetTable.fire(session, evaluateTriggerMasks(), false); targetTable.fire(session, evaluateTriggerMasks(), false);
return count; return countUpdatedRows;
} }
...@@ -136,57 +138,28 @@ public class MergeUsing extends Merge { ...@@ -136,57 +138,28 @@ public class MergeUsing extends Merge {
// put the column values into the table filter // put the column values into the table filter
sourceTableFilter.set(sourceRow); sourceTableFilter.set(sourceRow);
// try and update // try and perform an update
int count = 0; int count = 0;
System.out.println("onConditions="+onCondition.toString());
if(updateCommand!=null){ if(updateCommand!=null){
System.out.println("onConditions="+onCondition.toString());
System.out.println("updatePlanSQL="+updateCommand.getPlanSQL()); System.out.println("updatePlanSQL="+updateCommand.getPlanSQL());
count += updateCommand.update(); count += updateCommand.update();
System.out.println("update.count="+count); System.out.println("update.count="+count);
} }
if(deleteCommand!=null && count==0){ if(deleteCommand!=null && count==0){
System.out.println("deleteCommand="+deleteCommand.getPlanSQL());
count += deleteCommand.update(); count += deleteCommand.update();
System.out.println("delete.count="+count); System.out.println("delete.count="+count);
} }
// if either updates do nothing, try an insert // if either updates do nothing, try an insert
if (count == 0) { if (count == 0) {
try { count+=addRowByCommandInsert(session,newTargetRow);
targetTable.validateConvertUpdateSequence(session, newTargetRow); //addRowByAPIInsert(session,newTargetRow);
boolean done = targetTable.fireBeforeRow(session, null, newTargetRow);
if (!done) {
targetTable.lock(session, true, false);
//targetTable.addRow(session, row);
addRowByInsert(session,newTargetRow);
session.log(targetTable, UndoLogRecord.INSERT, newTargetRow);
targetTable.fireAfterRow(session, null, newTargetRow, false);
}
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.DUPLICATE_KEY_1) {
// possibly a concurrent merge or insert
Index index = (Index) e.getSource();
if (index != null) {
// verify the index columns match the key
Column[] indexColumns = index.getColumns();
boolean indexMatchesKeys = true;
if (indexColumns.length <= keys.length) {
for (int i = 0; i < indexColumns.length; i++) {
if (indexColumns[i] != keys[i]) {
indexMatchesKeys = false;
break;
}
}
}
if (indexMatchesKeys) {
throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, targetTable.getName());
}
}
}
throw e;
}
} else if (count != 1) { } else if (count != 1) {
throw DbException.get(ErrorCode.DUPLICATE_KEY_1, targetTable.getSQL()); throw DbException.get(ErrorCode.DUPLICATE_KEY_1, targetTable.getSQL());
} }
countUpdatedRows+=count;
} }
...@@ -211,10 +184,53 @@ public class MergeUsing extends Merge { ...@@ -211,10 +184,53 @@ public class MergeUsing extends Merge {
p.setValue(v); p.setValue(v);
} }
} }
private int addRowByCommandInsert(Session session, Row newTargetRow) {
int localCount = 0;
if(insertCommand!=null){
System.out.println("insertPlanSQL="+insertCommand.getPlanSQL());
localCount += insertCommand.update();
}
System.out.println("insert.count="+localCount);
return localCount;
}
private void addRowByInsert(Session session, Row row) { private int addRowByAPIInsert(Session session, Row newTargetRow) {
System.out.println("addRowByInsert=(hashcode)"+row.hashCode()); System.out.println("addRowByInsert=(hashcode)"+newTargetRow.hashCode());
targetTable.addRow(session, row); try {
targetTable.validateConvertUpdateSequence(session, newTargetRow);
boolean done = targetTable.fireBeforeRow(session, null, newTargetRow);
if (!done) {
targetTable.lock(session, true, false);
targetTable.addRow(session, newTargetRow);
session.log(targetTable, UndoLogRecord.INSERT, newTargetRow);
targetTable.fireAfterRow(session, null, newTargetRow, false);
return 1;
}
return 0;
} catch (DbException e) {
if (e.getErrorCode() == ErrorCode.DUPLICATE_KEY_1) {
// possibly a concurrent merge or insert
Index index = (Index) e.getSource();
if (index != null) {
// verify the index columns match the key
Column[] indexColumns = index.getColumns();
boolean indexMatchesKeys = true;
if (indexColumns.length <= keys.length) {
for (int i = 0; i < indexColumns.length; i++) {
if (indexColumns[i] != keys[i]) {
indexMatchesKeys = false;
break;
}
}
}
if (indexMatchesKeys) {
throw DbException.get(ErrorCode.CONCURRENT_UPDATE_1, targetTable.getName());
}
}
}
throw e;
}
} }
...@@ -347,13 +363,28 @@ public class MergeUsing extends Merge { ...@@ -347,13 +363,28 @@ public class MergeUsing extends Merge {
throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH); throw DbException.get(ErrorCode.COLUMN_COUNT_DOES_NOT_MATCH);
} }
} }
// if (keys == null) {
// Index idx = targetTable.getPrimaryKey();
// if (idx == null) {
// throw DbException.get(ErrorCode.CONSTRAINT_NOT_FOUND_1, "PRIMARY KEY");
// }
// keys = idx.getColumns();
// }
if (keys == null) { if (keys == null) {
Index idx = targetTable.getPrimaryKey(); HashSet<Column> targetColumns = new HashSet<Column>();
if (idx == null) { HashSet<Column> columns = new HashSet<Column>();
throw DbException.get(ErrorCode.CONSTRAINT_NOT_FOUND_1, "PRIMARY KEY"); ExpressionVisitor visitor = ExpressionVisitor.getColumnsVisitor(columns);
onCondition.isEverything(visitor);
for(Column c: columns){
if(c.getTable()==targetTable){
targetColumns.add(c);
}
} }
keys = idx.getColumns(); if (targetColumns.isEmpty()) {
} throw DbException.get(ErrorCode.CONSTRAINT_NOT_FOUND_1, "ON (condition) target columns missing");
}
keys = targetColumns.toArray(new Column[1]);
}
String sql = buildPreparedSQL(); String sql = buildPreparedSQL();
update = session.prepare(sql); update = session.prepare(sql);
...@@ -389,7 +420,7 @@ public class MergeUsing extends Merge { ...@@ -389,7 +420,7 @@ public class MergeUsing extends Merge {
} }
return new ConditionAndOr(ConditionAndOr.AND,deleteCommand.getCondition(),onCondition); return new ConditionAndOr(ConditionAndOr.AND,deleteCommand.getCondition(),onCondition);
} }
private String buildPreparedSQL() { private String buildPreparedSQL() {
StatementBuilder buff = new StatementBuilder("UPDATE "); StatementBuilder buff = new StatementBuilder("UPDATE ");
buff.append(targetTable.getSQL()); buff.append(targetTable.getSQL());
...@@ -410,6 +441,44 @@ public class MergeUsing extends Merge { ...@@ -410,6 +441,44 @@ public class MergeUsing extends Merge {
String sql = buff.toString(); String sql = buff.toString();
return sql; return sql;
} }
private String buildPreparedSQLForMergeUsing() {
StatementBuilder buff = new StatementBuilder("MERGE INTO ");
buff.append(targetTable.getSQL());
if(targetTableFilter.getTableAlias()!=null){
buff.append(" AS "+targetTableFilter.getTableAlias()+"\n");
}
buff.append("USING \n");
buff.append(temporarySourceTableView.getSQL());
buff.append("\n");
if(sourceTableFilter.getTableAlias()!=null){
buff.append(" AS "+sourceTableFilter.getTableAlias()+"\n");
}
buff.append("ON (");
buff.append(onCondition.getSQL());
buff.append(" )");
if(updateCommand!=null || deleteCommand!=null){
buff.append("\nWHEN MATCHED\n");
if(updateCommand!=null){
buff.append(updateCommand.getPlanSQL());
}
if(deleteCommand!=null){
buff.append(deleteCommand.getPlanSQL());
}
}
if(insertCommand!=null){
buff.append("\nWHEN NOT MATCHED\n");
if(insertCommand!=null){
buff.append(insertCommand.getPlanSQL());
}
}
// buff.resetCount();
// for (Column c : keys) {
// buff.appendExceptFirst(" AND ");
// buff.append(c.getSQL()).append("=?");
// }
String sql = buff.toString();
return sql;
}
public void setSourceTableFilter(TableFilter sourceTableFilter) { public void setSourceTableFilter(TableFilter sourceTableFilter) {
this.sourceTableFilter = sourceTableFilter; this.sourceTableFilter = sourceTableFilter;
......
...@@ -361,7 +361,7 @@ public class Session extends SessionWithState { ...@@ -361,7 +361,7 @@ public class Session extends SessionWithState {
} }
if (localTempTables.get(table.getName()) != null) { if (localTempTables.get(table.getName()) != null) {
throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1, throw DbException.get(ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1,
table.getSQL()); table.getSQL()+" AS "+table.getName());
} }
modificationId++; modificationId++;
localTempTables.put(table.getName(), table); localTempTables.put(table.getName(), table);
......
...@@ -9,7 +9,6 @@ import java.sql.Connection; ...@@ -9,7 +9,6 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import org.h2.test.TestBase; import org.h2.test.TestBase;
/** /**
* Test merge using syntax. * Test merge using syntax.
...@@ -17,6 +16,8 @@ import org.h2.test.TestBase; ...@@ -17,6 +16,8 @@ import org.h2.test.TestBase;
public class TestMergeUsing extends 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. * Run just this test.
* *
...@@ -28,35 +29,86 @@ public class TestMergeUsing extends TestBase { ...@@ -28,35 +29,86 @@ public class TestMergeUsing extends TestBase {
@Override @Override
public void test() throws Exception { 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"); deleteDb("mergeUsingQueries");
Connection conn = getConnection("mergeUsingQueries"); Connection conn = getConnection("mergeUsingQueries");
Statement stat; Statement stat;
PreparedStatement prep; PreparedStatement prep;
ResultSet rs; ResultSet rs;
int rowCount; int rowCountUpdate;
stat = conn.createStatement(); 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();
int[] rowArray = new int[] { 1,2 }; prep = conn.prepareStatement(statementUnderTest);
assertEquals(rowArray.length,rowCount); rowCountUpdate = prep.executeUpdate();
rs = stat.executeQuery("SELECT ID, NAME FROM PARENT ORDER BY ID ASC"); rs = stat.executeQuery("( "+gatherResultsSQL+" ) MINUS ( "+expectedResultsSQL+" )");
for (int n : rowArray) { int rowCount = 0;
assertTrue(rs.next()); StringBuffer diffBuffer = new StringBuffer("");
assertEquals(n,rs.getInt(1)); while (rs.next()) {
assertEquals("Marcy"+n, rs.getString(2)); rowCount++;
System.out.println("id="+rs.getInt(1)+",name="+rs.getString(2)); 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(); conn.close();
deleteDb("mergeUsingQueries"); deleteDb("mergeUsingQueries");
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论