/* * 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.query.processor.relational; import static org.junit.Assert.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.junit.Test; import org.mockito.Mockito; import org.teiid.common.buffer.BlockedException; import org.teiid.common.buffer.BufferManager; import org.teiid.common.buffer.TupleBatch; import org.teiid.common.buffer.TupleSource; import org.teiid.core.TeiidComponentException; import org.teiid.events.EventDistributor; import org.teiid.query.metadata.QueryMetadataInterface; import org.teiid.query.optimizer.TestBatchedUpdatePlanner; import org.teiid.query.processor.ProcessorDataManager; import org.teiid.query.processor.RegisterRequestParameter; import org.teiid.query.sql.lang.BatchedUpdateCommand; import org.teiid.query.sql.lang.Command; import org.teiid.query.sql.visitor.EvaluatableVisitor; import org.teiid.query.unittest.RealMetadataFactory; import org.teiid.query.util.CommandContext; /** * @since 4.2 */ public class TestBatchedUpdateNode { private BatchedUpdateNode helpGetNode(String[] sql, QueryMetadataInterface md, ProcessorDataManager pdm) throws Exception { List<Command> commands = TestBatchedUpdatePlanner.helpGetCommands(sql, md); List<Boolean> shouldEvaluate = new ArrayList<Boolean>(commands.size()); for (Command command : commands) { shouldEvaluate.add(EvaluatableVisitor.needsProcessingEvaluation(command)); } BatchedUpdateNode node = new BatchedUpdateNode(1, commands, Collections.EMPTY_LIST, shouldEvaluate, "myModelName"); //$NON-NLS-1$ CommandContext context = new CommandContext(); context.setMetadata(md); node.initialize(context, Mockito.mock(BufferManager.class), pdm); return node; } private BatchedUpdateNode helpOpen(String[] commands, ProcessorDataManager pdm) throws Exception { BatchedUpdateNode node = helpGetNode(commands, RealMetadataFactory.example1Cached(), pdm); node.open(); return node; } private void helpTestOpen(String[] commands, String[] expectedCommands) throws Exception { FakePDM pdm = new FakePDM(expectedCommands.length); helpOpen(commands, pdm); assertEquals(Arrays.asList(expectedCommands), pdm.commands); } private FakePDM helpTestNextBatch(String[] commands, int[] expectedResults) throws Exception { int numExecutedCommands = 0; for (int i = 0; i < expectedResults.length; i++) { numExecutedCommands += expectedResults[i]; } FakePDM fakePDM = new FakePDM(numExecutedCommands); BatchedUpdateNode node = helpOpen(commands, fakePDM); TupleBatch batch = null; try { batch = node.nextBatch(); } catch (BlockedException e) { batch = node.nextBatch(); } assertNotNull(batch); assertTrue(batch.getTerminationFlag()); assertEquals(expectedResults.length, batch.getRowCount()); for (int i = 0; i < expectedResults.length; i++) { List tuple = batch.getTuple(i+1); assertNotNull(tuple); Object result = tuple.get(0); assertNotNull(result); assertEquals(new Integer(expectedResults[i]), result); } return fakePDM; } @Test public void testOpen1() throws Exception { String[] sql = {"INSERT INTO pm1.g1 (e1, e2, e3, e4) values ('string1', 1, {b'true'}, 1.0)", //$NON-NLS-1$ "INSERT INTO pm1.g2 (e1, e2, e3, e4) values ('string1', 1, {b'true'}, 1.0)" //$NON-NLS-1$ }; String[] expectedCommands = {"BatchedUpdate{I,I}"}; //$NON-NLS-1$ helpTestOpen(sql, expectedCommands); } @Test public void testOpen2() throws Exception { String[] sql = {"INSERT INTO pm1.g1 (e1, e2, e3, e4) values ('string1', 1, {b'true'}, 1.0)", //$NON-NLS-1$ "UPDATE pm1.g1 SET e2 = 50 WHERE e1 = 'criteria'", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE e2 = 50", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE e2 = 100" //$NON-NLS-1$ }; String[] expectedCommands = {"BatchedUpdate{I,U,D,D}"}; //$NON-NLS-1$ helpTestOpen(sql, expectedCommands); } @Test public void testOpenAllCommandsExecuted() throws Exception { String[] sql = {"UPDATE pm1.g1 SET e2 = 50 WHERE e1 = 'criteria'", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE e2 = 50", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE e1 = 'myrow'" //$NON-NLS-1$ }; String[] expectedCommands = {"BatchedUpdate{U,D,U}"}; //$NON-NLS-1$ helpTestOpen(sql, expectedCommands); } @Test public void testOpenNoCommandsExecuted() throws Exception { String[] sql = {"UPDATE pm1.g1 SET e2 = 50 WHERE 1 = 0", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE 1 = 0", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE 1 = 0" //$NON-NLS-1$ }; String[] expectedCommands = {}; helpTestOpen(sql, expectedCommands); } @Test public void testOpenSomeCommandsExecuted() throws Exception { String[] sql = {"UPDATE pm1.g1 SET e2 = 50 WHERE e1 = 'criteria'", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE 1 = 0", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE e1 = 'myrow'" //$NON-NLS-1$ }; String[] expectedCommands = {"BatchedUpdate{U,U}"}; //$NON-NLS-1$ helpTestOpen(sql, expectedCommands); } @Test public void testNextBatch1() throws Exception { String[] commands = {"INSERT INTO pm1.g1 (e1, e2, e3, e4) values ('string1', 1, {b'true'}, 1.0)", //$NON-NLS-1$ "INSERT INTO pm1.g2 (e1, e2, e3, e4) values ('string1', 1, {b'true'}, 1.0)" //$NON-NLS-1$ }; int[] expectedResults = {1,1}; helpTestNextBatch(commands, expectedResults); } @Test public void testNextBatch2() throws Exception { String[] commands = {"INSERT INTO pm1.g1 (e1, e2, e3, e4) values ('string1', 1, {b'true'}, 1.0)", //$NON-NLS-1$ "UPDATE pm1.g1 SET e2 = 50 WHERE e1 = 'criteria'", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE e2 = 50", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE e2 = 100" //$NON-NLS-1$ }; int[] expectedResults = {1,1,1,1}; helpTestNextBatch(commands, expectedResults); } @Test public void testNextBatchAllcommandsExecuted() throws Exception { String[] commands = {"UPDATE pm1.g1 SET e2 = 50 WHERE e1 = 'criteria'", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE e2 = 50", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE e1 = 'myrow'" //$NON-NLS-1$ }; int[] expectedResults = {1,1,1}; helpTestNextBatch(commands, expectedResults); } @Test public void testNextBatchNoCommandsExecuted() throws Exception { String[] commands = {"UPDATE pm1.g1 SET e2 = 50 WHERE 1 = 0", //$NON-NLS-1$ "DELETE FROM pm1.g2 WHERE 1 = 0", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE 1 = 0" //$NON-NLS-1$ }; int[] expectedResults = {0,0,0}; helpTestNextBatch(commands, expectedResults); } @Test public void testNextBatchSomeCommandsExecuted() throws Exception { String[] commands = {"DELETE FROM pm1.g2 WHERE 1 = 0", //$NON-NLS-1$ "UPDATE pm1.g1 SET e2 = 50 WHERE e1 = 'criteria'", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE e1 = 'myrow'", //$NON-NLS-1$ "UPDATE pm1.g2 set e2 = 5, e3 = {b'false'}, e4 = 3.33 WHERE 1 = 0" //$NON-NLS-1$ }; int[] expectedResults = {0,1,1,0}; helpTestNextBatch(commands, expectedResults); } @Test public void testNextBatchCommandNeedsEvaluated() throws Exception { String[] commands = {"INSERT INTO pm1.g1 (e1, e2, e3, e4) values (commandpayload(), 1, {b'true'}, 1.0)" //$NON-NLS-1$ }; int[] expectedResults = {1}; FakePDM fpdm = helpTestNextBatch(commands, expectedResults); assertEquals("INSERT INTO pm1.g1 (e1, e2, e3, e4) VALUES (null, 1, TRUE, 1.0)", ((BatchedUpdateCommand)fpdm.actualCommands.get(0)).getUpdateCommands().get(0).toString()); //$NON-NLS-1$ } private static final class FakePDM implements ProcessorDataManager { private int numExecutedCommands; private List<String> commands = new ArrayList<String>(); private List<Command> actualCommands = new ArrayList<Command>(); private FakePDM(int numExecutedCommands) { this.numExecutedCommands = numExecutedCommands; } public Object lookupCodeValue(CommandContext context,String codeTableName,String returnElementName,String keyElementName,Object keyValue) throws BlockedException,TeiidComponentException {return null;} public TupleSource registerRequest(CommandContext context,Command command,String modelName,RegisterRequestParameter parameterObject) throws TeiidComponentException { assertEquals("myModelName", modelName); //$NON-NLS-1$ assertEquals(1, parameterObject.nodeID); commands.add(command.toString()); actualCommands.add(command); return new FakeTupleSource(numExecutedCommands); } @Override public EventDistributor getEventDistributor() { // TODO Auto-generated method stub return null; } } private static final class FakeTupleSource implements TupleSource { private int currentTuple = 0; private int numCommands; private boolean first = true; private FakeTupleSource(int numCommands) { this.numCommands = numCommands; } public void closeSource() {} public List nextTuple() throws TeiidComponentException { if (first) { first = false; throw BlockedException.INSTANCE; } if (currentTuple++ < numCommands) { return Arrays.asList(new Object[] {new Integer(1)}); } return null; } } }