Author: loleary
Date: 2009-04-23 17:26:48 -0400 (Thu, 23 Apr 2009)
New Revision: 837
Added:
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java
Modified:
trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java
trunk/engine/src/test/java/com/metamatrix/query/processor/TestVirtualDepJoin.java
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java
Log:
TEIID-532: Added UnitTests to cover BatchedUpdate within PreparedStatement.
Reviewed by: ghelblin
Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java
===================================================================
---
trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java 2009-04-23
21:24:27 UTC (rev 836)
+++
trunk/engine/src/test/java/com/metamatrix/query/processor/FakeDataManager.java 2009-04-23
21:26:48 UTC (rev 837)
@@ -23,6 +23,7 @@
package com.metamatrix.query.processor;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -37,11 +38,14 @@
import com.metamatrix.common.log.LogManager;
import com.metamatrix.query.eval.Evaluator;
import com.metamatrix.query.metadata.TempMetadataID;
+import com.metamatrix.query.sql.lang.BatchedUpdateCommand;
import com.metamatrix.query.sql.lang.Command;
+import com.metamatrix.query.sql.lang.CommandContainer;
import com.metamatrix.query.sql.lang.From;
import com.metamatrix.query.sql.lang.ProcedureContainer;
import com.metamatrix.query.sql.lang.Query;
import com.metamatrix.query.sql.lang.SetQuery;
+import com.metamatrix.query.sql.lang.Update;
import com.metamatrix.query.sql.symbol.AliasSymbol;
import com.metamatrix.query.sql.symbol.ElementSymbol;
import com.metamatrix.query.sql.symbol.GroupSymbol;
@@ -71,7 +75,7 @@
private Map blockedState = new HashMap();
// Track history to verify it later
- private Set queries = new HashSet();
+ private List<String> queries = new ArrayList<String>();
public FakeDataManager() {
}
@@ -80,7 +84,7 @@
* Return string form of all queries run against this FDM
* @return List<String>
*/
- public Set getQueries() {
+ public List<String> getQueries() {
return this.queries;
}
@@ -89,6 +93,7 @@
}
public void closeRequest(Object requestID) {
+ // does nothing?
}
public TupleSource registerRequest(Object processorID, Command command, String
modelName, String connectorBindingId, int nodeID)
@@ -96,7 +101,18 @@
LogManager.logTrace(LOG_CONTEXT, new Object[]{"Register Request:",
command, ",processorID:", processorID, ",model name:",
modelName,",TupleSourceID nodeID:",new Integer(nodeID)}); //$NON-NLS-1$
//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
- queries.add(command.toString());
+
+ if ( command instanceof CommandContainer ) {
+ if ( ((CommandContainer) command).getContainedCommands() != null &&
((CommandContainer) command).getContainedCommands().size() > 0 ) {
+ for ( Iterator<Command> it = ((CommandContainer)
command).getContainedCommands().iterator(); it.hasNext(); ) {
+ this.queries.add(it.next().toString());
+ }
+ } else {
+ this.queries.add(command.toString());
+ }
+ } else {
+ this.queries.add(command.toString());
+ }
if (ReferenceCollectorVisitor.getReferences(command).size() > 0) {
throw new IllegalArgumentException("Found references in the command
registered with the DataManager."); //$NON-NLS-1$
@@ -108,8 +124,14 @@
}else if(command instanceof SetQuery) {
SetQuery union = (SetQuery) command;
group = getQueryGroup(union.getProjectedQuery());
- }else if(command instanceof ProcedureContainer){
- group = ((ProcedureContainer)command).getGroup();
+ } else if (command instanceof ProcedureContainer) {
+ group = ((ProcedureContainer) command).getGroup();
+ } else if ( command instanceof BatchedUpdateCommand ) {
+ if ( ((CommandContainer) command).getContainedCommands() != null &&
((CommandContainer) command).getContainedCommands().size() > 0 ) {
+ if ( command.getSubCommands().get(0) instanceof Update ) {
+ group = ((Update)command.getSubCommands().get(0)).getGroup();
+ }
+ }
}
Object groupID = group.getMetadataID();
@@ -121,6 +143,13 @@
List projectedSymbols = command.getProjectedSymbols();
int[] columnMap = getColumnMap(elements, projectedSymbols);
+ /*
+ * updateCommands is used to hold a list of commands that
+ * either came from a BatchedUpdateCommand or a signle
+ * command from an Update command.
+ */
+ List<Update> updateCommands = new ArrayList<Update>();
+
// Apply query criteria to tuples
if(command instanceof Query){
Query query = (Query)command;
@@ -150,6 +179,54 @@
tuples = new List[filteredTuples.size()];
filteredTuples.toArray(tuples);
}
+ } else if ( command instanceof Update ) {
+ // add single update command to a list to be executed
+ updateCommands.add((Update)command);
+ } else if ( command instanceof BatchedUpdateCommand ) {
+ if ( ((CommandContainer) command).getContainedCommands() != null &&
((CommandContainer) command).getContainedCommands().size() > 0 )
+ // add all update commands to a list to be executed
+ for ( int i = 0; i < ((CommandContainer)
command).getContainedCommands().size(); i++ )
+ if ( ((CommandContainer) command).getContainedCommands().get(i) instanceof
Update ) {
+ updateCommands.add(((Update) ((CommandContainer)
command).getContainedCommands().get(i)));
+ }
+ }
+
+ // if we had update commands added to the list, execute them now
+ if ( updateCommands.size() > 0 ) {
+ List<List<Integer>> filteredTuples = new
ArrayList<List<Integer>>();
+ for ( int c = 0; c < updateCommands.size(); c++ ) {
+ Update update = (Update)updateCommands.get(c);
+ if ( update.getCriteria() != null ) {
+ // Build lookupMap from BOTH all the elements and the projected symbols - both
may be needed here
+ Map<Object, Integer> lookupMap = new HashMap<Object,
Integer>();
+ for(int i=0; i<elements.size(); i++) {
+ Object element = elements.get(i);
+ mapElementToIndex(lookupMap, element, new Integer(i), group);
+ }
+ for(int i=0; i<projectedSymbols.size(); i++) {
+ Object element = projectedSymbols.get(i);
+ mapElementToIndex(lookupMap, element, new Integer(columnMap[i]),
group);
+ }
+
+ int updated = 0;
+ for(int i=0; i<tuples.length; i++) {
+ try {
+ if(new Evaluator(lookupMap, null, null).evaluate(update.getCriteria(),
tuples[i])) {
+ updated++;
+ }
+ } catch(CriteriaEvaluationException e) {
+ throw new MetaMatrixComponentException(e, e.getMessage());
+ }
+ }
+ List<Integer> updateTuple = new ArrayList<Integer>(1);
+ updateTuple.add( new Integer(updated) );
+ filteredTuples.add(updateTuple);
+ }
+ }
+ tuples = new List[filteredTuples.size()];
+ filteredTuples.toArray(tuples);
+ elements = new ArrayList<Object>(projectedSymbols);
+ columnMap[0] = 0;
}
FakeTupleSource ts= new FakeTupleSource(elements, tuples, projectedSymbols,
columnMap);
Modified:
trunk/engine/src/test/java/com/metamatrix/query/processor/TestVirtualDepJoin.java
===================================================================
---
trunk/engine/src/test/java/com/metamatrix/query/processor/TestVirtualDepJoin.java 2009-04-23
21:24:27 UTC (rev 836)
+++
trunk/engine/src/test/java/com/metamatrix/query/processor/TestVirtualDepJoin.java 2009-04-23
21:26:48 UTC (rev 837)
@@ -24,6 +24,7 @@
import java.math.BigDecimal;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
@@ -219,7 +220,7 @@
// Second query *will not be run* as no values were passed and dependent side has
always false criteria
// So, the list should contain only the first query
- assertEquals(1, dataManager.getQueries().size());
+ assertEquals(3, dataManager.getQueries().size());
}
public void helpTestVirtualDepJoinSourceSelection(boolean setPushdown) throws
Exception {
@@ -389,8 +390,13 @@
// Run query
TestProcessor.helpProcess(plan, context, dataManager, expected);
- assertEquals(new HashSet<String>(Arrays.asList("SELECT g_0.id AS c_0,
g_0.amount AS c_1 FROM Europe.CustAccts AS g_0 WHERE g_0.id = 100 ORDER BY c_0",
"SELECT g_0.id AS c_0, g_0.first AS c_1, g_0.last AS c_2 FROM
CustomerMaster.Customers AS g_0 WHERE g_0.first = 'Miles' ORDER BY c_0")),
//$NON-NLS-1$ //$NON-NLS-2$
- dataManager.getQueries());
+ List<String> expectedQueries = new ArrayList<String>(6);
+ for (int i = 0; i < 3; i++) {
+ expectedQueries.add("SELECT g_0.id AS c_0, g_0.first AS c_1, g_0.last AS
c_2 FROM CustomerMaster.Customers AS g_0 WHERE g_0.first = 'Miles' ORDER BY
c_0"); //$NON-NLS-1$
+ expectedQueries.add("SELECT g_0.id AS c_0, g_0.amount AS c_1 FROM
Europe.CustAccts AS g_0 WHERE g_0.id = 100 ORDER BY c_0"); //$NON-NLS-1$
+ }
+
+ assertEquals(expectedQueries, dataManager.getQueries());
}
public void testVirtualDepJoinSelects() throws Exception {
Modified:
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java 2009-04-23
21:24:27 UTC (rev 836)
+++
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatement.java 2009-04-23
21:26:48 UTC (rev 837)
@@ -80,38 +80,74 @@
}
static void helpTestProcessing(String preparedSql, List values, List[] expected,
QueryMetadataInterface metadata, boolean callableStatement) throws Exception {
- // Construct data manager with data
- FakeDataManager dataManager = new FakeDataManager();
- TestProcessor.sampleData1(dataManager);
-
- helpTestProcessing(preparedSql, values, expected, dataManager, metadata,
callableStatement);
+ helpTestProcessing(preparedSql, values, expected, (ProcessorDataManager)null,
metadata, callableStatement);
}
static void helpTestProcessing(String preparedSql, List values, List[] expected,
ProcessorDataManager dataManager, QueryMetadataInterface metadata, boolean
callableStatement) throws Exception {
helpTestProcessing(preparedSql, values, expected, dataManager, metadata,
callableStatement, false);
}
- static void helpTestProcessing(String preparedSql, List values, List[] expected,
ProcessorDataManager dataManager, QueryMetadataInterface metadata, boolean
callableStatement, boolean differentPlan) throws Exception {
- TestablePreparedPlanCache prepPlan = new TestablePreparedPlanCache();
- //Create plan
- PreparedStatementRequest plan =
TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, new
DefaultCapabilitiesFinder(), metadata, prepPlan, SESSION_ID, callableStatement, false);
+ static void helpTestProcessing(String preparedSql, List values, List[] expected,
ProcessorDataManager dataManager, QueryMetadataInterface metadata, boolean
callableStatement, boolean isSessionSpecific) throws Exception {
+ helpTestProcessing(preparedSql, values, expected, dataManager,
(CapabilitiesFinder)null, metadata, (TestablePreparedPlanCache)null, callableStatement,
isSessionSpecific, /* isAlreadyCached */false);
+ }
+
+ static public void helpTestProcessing(String preparedSql, List values, List[]
expected, ProcessorDataManager dataManager, CapabilitiesFinder capFinder,
QueryMetadataInterface metadata, TestablePreparedPlanCache prepPlanCache, boolean
callableStatement, boolean isSessionSpecific, boolean isAlreadyCached) throws Exception {
+ TestablePreparedPlanCache pPlanCache = null;
+ CapabilitiesFinder cFinder = null;
+ ProcessorDataManager dManager = null;
+
+ if ( dataManager == null ) {
+ // Construct data manager with data
+ dManager = new FakeDataManager();
+ TestProcessor.sampleData1((FakeDataManager)dManager);
+ } else dManager = dataManager;
+
+ if ( capFinder == null ) cFinder = new DefaultCapabilitiesFinder();
+ else cFinder = capFinder;
+
+ if ( prepPlanCache == null ) pPlanCache = new TestablePreparedPlanCache();
+ else pPlanCache = prepPlanCache;
+
+ // expected cache hit count
+ int exHitCount = -1;
+
+ /*
+ * If the plan is already cached we want our expected hit
+ * count of the cache to be at least 2 because we will
+ * get the plan twice. Otherwise, we want it to be 1.
+ */
+ if ( isAlreadyCached ) {
+ exHitCount = pPlanCache.hitCount + 2;
+ } else {
+ exHitCount = pPlanCache.hitCount + 1;
+ }
+
+ //Create plan or used cache plan if isPlanCached
+ PreparedStatementRequest plan =
TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, cFinder, metadata,
pPlanCache, SESSION_ID, callableStatement, false);
// Run query
- TestProcessor.helpProcess(plan.processPlan, plan.context, dataManager,
expected);
+ TestProcessor.helpProcess(plan.processPlan, plan.context, dManager, expected);
//test cached plan
- plan = TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, new
DefaultCapabilitiesFinder(), metadata, prepPlan, SESSION_ID, callableStatement, false);
+ plan = TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, cFinder,
metadata, pPlanCache, SESSION_ID, callableStatement, false);
//make sure the plan is only created once
- assertEquals("should reuse the plan", 1, prepPlan.hitCount);
//$NON-NLS-1$
+ assertEquals("should reuse the plan", exHitCount, pPlanCache.hitCount);
//$NON-NLS-1$
// Run query again
- TestProcessor.helpProcess(plan.processPlan, plan.context, dataManager,
expected);
+ TestProcessor.helpProcess(plan.processPlan, plan.context, dManager, expected);
//get the plan again with a new connection
- assertNotNull(TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, new
DefaultCapabilitiesFinder(), metadata, prepPlan, 7, callableStatement, false));
+ assertNotNull(TestPreparedStatement.helpGetProcessorPlan(preparedSql, values,
cFinder, metadata, pPlanCache, 7, callableStatement, false));
- assertEquals(differentPlan?1:2, prepPlan.hitCount);
+ /*
+ * If the command is not specific to a session we expect
+ * another hit against the cache because we will use the
+ * cached plan, otherwise, a new plan would have been
+ * created and the hit count will be unchanged.
+ */
+ if ( !isSessionSpecific ) exHitCount++;
+ assertEquals(exHitCount, pPlanCache.hitCount);
}
public void testWhere() throws Exception {
@@ -181,14 +217,14 @@
TestOptimizer.checkNodeTypes(plan.processPlan, TestOptimizer.FULL_PUSHDOWN);
}
- private PreparedStatementRequest helpGetProcessorPlan(String preparedSql, List values,
PreparedPlanCache prepPlanCache)
+ static public PreparedStatementRequest helpGetProcessorPlan(String preparedSql, List
values, PreparedPlanCache prepPlanCache)
throws MetaMatrixComponentException, QueryParserException,
QueryResolverException, QueryValidatorException,
QueryPlannerException {
return helpGetProcessorPlan(preparedSql, values, new DefaultCapabilitiesFinder(),
FakeMetadataFactory.example1Cached(), prepPlanCache, SESSION_ID, false, false);
}
- private PreparedStatementRequest helpGetProcessorPlan(String preparedSql, List values,
+ static public PreparedStatementRequest helpGetProcessorPlan(String preparedSql, List
values,
PreparedPlanCache prepPlanCache, int conn)
throws MetaMatrixComponentException, QueryParserException,
QueryResolverException, QueryValidatorException,
@@ -209,6 +245,9 @@
request.setPreparedStatement(true);
request.setCallableStatement(callableStatement);
request.setParameterValues(values);
+ if (values != null && values.size() > 0 && values.get(0) instanceof
List) {
+ request.setPreparedBatchUpdate(true);
+ }
if (limitResults) {
request.setRowLimit(1);
}
Added:
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java
(rev 0)
+++
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java 2009-04-23
21:26:48 UTC (rev 837)
@@ -0,0 +1,252 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.dqp.internal.process;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.teiid.dqp.internal.process.TestPreparedStatement.TestablePreparedPlanCache;
+
+import com.metamatrix.query.optimizer.capabilities.BasicSourceCapabilities;
+import com.metamatrix.query.optimizer.capabilities.FakeCapabilitiesFinder;
+import com.metamatrix.query.optimizer.capabilities.SourceCapabilities.Capability;
+import com.metamatrix.query.processor.FakeDataManager;
+import com.metamatrix.query.processor.TestProcessor;
+import com.metamatrix.query.unittest.FakeMetadataFactory;
+
+/**
+ * JUnit TestCase to test planning and caching of
<code>PreparedStatement</code>
+ * plans that contain batched updates.
+ *
+ */
+public class TestPreparedStatementBatchedUpdate extends TestCase {
+
+ public TestPreparedStatementBatchedUpdate(String name) {
+ super(name);
+ }
+
+ /**
+ * Test prepared statements that use batched updates using the same prepared
+ * command with varying number of commands in the batch.
+ * <p>
+ * The test verifies that no errors occur when planning the same batched
+ * command SQL with varying number of batched command parameter value sets.
+ * For example, if the first executeBatch() call were to occur with three
+ * batched commands a repeated call with only two batched commands should
+ * not result in an error.
+ * <p>
+ * The test also verifies that a cached version of the PreparedStatement plan
+ * is used on each subsequent execution of the same SQL command even though
+ * the number of batched commands may vary.
+ * <p>
+ * The batched command "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE
pm1.g1.e2=?"
+ * will appear as:
+ * <p>
+ * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
+ * UPDATE pm1.g1 SET pm1.g1.e1=null, pm1.g1.e3=false WHERE pm1.g1.e2=1
+ * <p>
+ * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
+ * <p>
+ * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
+ * UPDATE pm1.g1 SET pm1.g1.e1=null, pm1.g1.e3=false WHERE pm1.g1.e2=1
+ * UPDATE pm1.g1 SET pm1.g1.e1='c', pm1.g1.e3=true WHERE pm1.g1.e2=4
+ * UPDATE pm1.g1 SET pm1.g1.e1='b', pm1.g1.e3=true WHERE pm1.g1.e2=5
+ * <p>
+ * The result should be that only one command is in the plan cache and
+ * no plan creation or validation errors will occur.
+ *
+ * @throws Exception
+ */
+ public void testPlanCache_VarNumCmds() throws Exception {
+ // Create query
+ String preparedSql = "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE
pm1.g1.e2=?"; //$NON-NLS-1$
+
+ // Create PrepareedPlanCache
+ PreparedPlanCache prepPlanCache = new PreparedPlanCache();
+
+ // batch with two commands
+ ArrayList<ArrayList<Object>> values = new
ArrayList<ArrayList<Object>>(2);
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "a",
Boolean.FALSE, new Integer(0) } ) ) ); //$NON-NLS-1$
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { null,
Boolean.FALSE, new Integer(1) } ) ) );
+
+ //Create plan
+ TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, prepPlanCache);
+
+ // batch with one command
+ values = new ArrayList<ArrayList<Object>>(1);
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "a",
Boolean.FALSE, new Integer(0) } ) ) ); //$NON-NLS-1$
+
+ //Create plan
+ TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, prepPlanCache);
+
+ // batch with four commands
+ values = new ArrayList<ArrayList<Object>>(4);
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "a",
Boolean.FALSE, new Integer(0) } ) ) ); //$NON-NLS-1$
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { null,
Boolean.FALSE, new Integer(1) } ) ) );
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "c",
Boolean.TRUE, new Integer(4) } ) ) ); //$NON-NLS-1$
+ values.add( new ArrayList<Object>( Arrays.asList( new Object[] { "b",
Boolean.TRUE, new Integer(5) } ) ) ); //$NON-NLS-1$
+
+ //Create plan
+ TestPreparedStatement.helpGetProcessorPlan(preparedSql, values, prepPlanCache);
+ assertEquals("PreparedPlanCache size is invalid - ", 1,
prepPlanCache.getSpaceUsed() ); //$NON-NLS-1$
+ }
+
+ /**
+ * Test prepared statements that use batched updates using the same prepared
+ * command with varying number of commands in the batch.
+ * <p>
+ * The test verifies that no errors occur when planning and executing the
+ * same batched command SQL with varying number of batched command parameter
+ * value sets. For example, if the first executeBatch() call were to occur
+ * with two batched commands a repeated call with only one batched command
+ * should not result in an error during planning or execution.
+ * <p>
+ * The test also verifies that a cached version of the PreparedStatement plan
+ * is used on each subsequent execution of the same SQL command even though
+ * the number of batched commands may vary.
+ * <p>
+ * The test also verifies that the correct SQL is pushed to the data manager
+ * to verify that the parameter substitution occurred and is correct and the
+ * correct number of statements made it to the data manager for the respective
+ * batch.
+ * <p>
+ * The batched command "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE
pm1.g1.e2=?"
+ * will appear as:
+ * <p>
+ * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
+ * UPDATE pm1.g1 SET pm1.g1.e1=null, pm1.g1.e3=false WHERE pm1.g1.e2=1
+ * <p>
+ * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
+ * <p>
+ * UPDATE pm1.g1 SET pm1.g1.e1='a', pm1.g1.e3=false WHERE pm1.g1.e2=0
+ * UPDATE pm1.g1 SET pm1.g1.e1=null, pm1.g1.e3=false WHERE pm1.g1.e2=1
+ * UPDATE pm1.g1 SET pm1.g1.e1='c', pm1.g1.e3=true WHERE pm1.g1.e2=4
+ * UPDATE pm1.g1 SET pm1.g1.e1='b', pm1.g1.e3=true WHERE pm1.g1.e2=5
+ * <p>
+ * The result should be that only one command is in the plan cache and
+ * no plan creation, validation, or execution errors will occur and
+ * a predetermined set of queries were executed in the data manager.
+ *
+ * @throws Exception
+ */
+ public void testProcessor_VarNumCmds() throws Exception {
+ // Create query
+ String preparedSql = "UPDATE pm1.g1 SET pm1.g1.e1=?, pm1.g1.e3=? WHERE
pm1.g1.e2=?"; //$NON-NLS-1$
+
+ // Create a testable prepared plan cache
+ TestablePreparedPlanCache prepPlanCache = new TestablePreparedPlanCache();
+
+ // Construct data manager with data
+ FakeDataManager dataManager = new FakeDataManager();
+ TestProcessor.sampleData1(dataManager);
+
+ // Source capabilities must support batched updates
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ BasicSourceCapabilities caps = new BasicSourceCapabilities();
+ caps.setCapabilitySupport(Capability.BATCHED_UPDATES, true);
+ caps.setCapabilitySupport(Capability.PREPARED_BATCH_UPDATE, false);
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+
+ // Something to hold our final query list
+ List<String> finalQueryList = new ArrayList<String>(42);
+
+ // Create expected results
+ // first command should result in 2 rows affected
+ // second command should result in 2 rows affected
+ List<?>[] expected = new List[] {
+ Arrays.asList(new Object[] { new Integer(2) }),
+ Arrays.asList(new Object[] { new Integer(2) })
+ };
+
+ // batch with two commands
+ ArrayList<ArrayList<Object>> values = new
ArrayList<ArrayList<Object>>(2);
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",
Boolean.FALSE, new Integer(0) }))); //$NON-NLS-1$
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { null,
Boolean.FALSE, new Integer(1) })));
+
+ // Add our expected queries to the final query list
+ for ( int i = 0; i < 6; i++ ) {
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE
WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE
pm1.g1.e2 = 1")); //$NON-NLS-1$
+ }
+
+ // Create the plan and process the query
+ TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager,
capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, false);
+
+ // Repeat with different number of commands in batch
+ // Create expected results
+ // first command should result in 2 rows affected
+ expected = new List[] {
+ Arrays.asList(new Object[] { new Integer(2) })
+ };
+
+ // batch with one command
+ values = new ArrayList<ArrayList<Object>>(1);
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",
Boolean.FALSE, new Integer(0) }))); //$NON-NLS-1$
+
+ // Add our expected queries to the final query list
+ for (int i = 0; i < 6; i++) {
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE
WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+ }
+
+ // Use the cached plan and process the query
+ TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager,
capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
+
+ // Repeat with different number of commands in batch
+ // Create expected results
+ // first command should result in 2 rows affected
+ // second command should result in 2 rows affected
+ // third command should result in 0 rows affected
+ // fourth command should result in 0 rows affected
+ expected = new List[] {
+ Arrays.asList(new Object[] { new Integer(2) }),
+ Arrays.asList(new Object[] { new Integer(2) }),
+ Arrays.asList(new Object[] { new Integer(0) }),
+ Arrays.asList(new Object[] { new Integer(0) })
+ };
+
+ // batch with four commands
+ values = new ArrayList<ArrayList<Object>>(4);
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "a",
Boolean.FALSE, new Integer(0)} ))); //$NON-NLS-1$
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { null,
Boolean.FALSE, new Integer(1)} )));
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "c",
Boolean.TRUE, new Integer(4)} ))); //$NON-NLS-1$
+ values.add(new ArrayList<Object>(Arrays.asList(new Object[] { "b",
Boolean.TRUE, new Integer(5)} ))); //$NON-NLS-1$
+
+ // Add our expected queries to the final query list
+ for (int i = 0; i < 6; i++) {
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'a', e3 = FALSE
WHERE pm1.g1.e2 = 0")); //$NON-NLS-1$
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = null, e3 = FALSE WHERE
pm1.g1.e2 = 1")); //$NON-NLS-1$
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'c', e3 = TRUE
WHERE pm1.g1.e2 = 4")); //$NON-NLS-1$
+ finalQueryList.add(new String("UPDATE pm1.g1 SET e1 = 'b', e3 = TRUE
WHERE pm1.g1.e2 = 5")); //$NON-NLS-1$
+ }
+
+ TestPreparedStatement.helpTestProcessing(preparedSql, values, expected, dataManager,
capFinder, FakeMetadataFactory.example1Cached(), prepPlanCache, false, false, true);
+
+ // Verify all the queries that were run
+ assertNotNull(dataManager);
+ assertEquals("Unexpected queries executed -", finalQueryList,
dataManager.getQueries()); //$NON-NLS-1$
+ }
+
+}
Property changes on:
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestPreparedStatementBatchedUpdate.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain